Last active
March 30, 2025 19:37
-
-
Save dvygolov/c2077f391bd15ba2f75d7496afb47a67 to your computer and use it in GitHub Desktop.
This script adds 4 (+2) Facebook Autorules, read comment below
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| let api = 'https://graph.facebook.com/v14.0'; | |
| let headers = { | |
| "accept": "*/*", | |
| "accept-language": "en-US,en;q=0.9", | |
| "content-type": "application/x-www-form-urlencoded", | |
| "sec-ch-ua": "\"Google Chrome\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\"", | |
| "sec-ch-ua-mobile": "?0", | |
| "sec-ch-ua-platform": "\"Windows\"", | |
| "sec-fetch-dest": "empty", | |
| "sec-fetch-mode": "cors", | |
| "sec-fetch-site": "same-site" | |
| }; | |
| var cbo = await campUsesCBO(); | |
| await main(cbo); | |
| async function campUsesCBO(){ | |
| let accountId = require("BusinessUnifiedNavigationContext").adAccountID; | |
| let f = await fetch(`${api}/act_${accountId}/campaigns?fields=bid_strategy&access_token=${__accessToken}`, { | |
| "headers": headers, | |
| "referrer": "https://business.facebook.com/", | |
| "referrerPolicy": "origin-when-cross-origin", | |
| "body": null, | |
| "method": "GET", | |
| "mode": "cors", | |
| "credentials": "include" | |
| }); | |
| let camps = await f.json(); | |
| if (camps.data.length==0) return false; | |
| if (camps.data[0]?.bid_strategy??null!=null) | |
| return true; | |
| return false; | |
| } | |
| async function main(cbo){ | |
| if (cbo) | |
| alert("Your campaign uses CBO so we'll create auto-rules for campaigns!"); | |
| else | |
| alert("Your campaign does NOT use CBO so we'll create rules for adsets!"); | |
| let accountId = require("BusinessUnifiedNavigationContext").adAccountID; | |
| await clearRules(accountId); | |
| let maxCPA = prompt('Please write your maximum CPA:'); | |
| if (maxCPA == null) { | |
| alert('Max CPA not set, exiting...'); | |
| return; | |
| } | |
| let hour = parseInt(prompt(`At which hour should we switch ON ${cbo?"campaign":"adsets"}?`)); | |
| if (hour == null) { | |
| alert('Switch ON hour not set, exiting...'); | |
| return; | |
| } | |
| let name = `TurnOff ${cbo?'Campaign':'Adset'} Withoud Leads`; | |
| let evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[ | |
| {"field":"spent","operator":"GREATER_THAN","value":(maxCPA*100).toString()}, | |
| {"field":"offsite_conversion.fb_pixel_lead","operator":"LESS_THAN","value":"1"}, | |
| {"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"}, | |
| {"field":"time_preset","value":"TODAY","operator":"EQUAL"} | |
| ]}; | |
| let execSpec = { | |
| "execution_type":"PAUSE", | |
| "execution_options":[{"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"}] | |
| }; | |
| let schedSpec = {"schedule_type":"SEMI_HOURLY"}; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| name = `TurnOff ${cbo?'Campaign':'Adset'} With Expensive Leads`; | |
| evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[ | |
| {"field":"cost_per_lead_fb","operator":"GREATER_THAN","value":(maxCPA*100).toString()}, | |
| {"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"}, | |
| {"field":"time_preset","value":"TODAY","operator":"EQUAL"} | |
| ] | |
| }; | |
| execSpec = { | |
| "execution_type":"PAUSE", | |
| "execution_options":[ | |
| {"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"} | |
| ]}; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| name = `TurnOn ${cbo?'Campaign':'Adset'} With Cheap Leads`; | |
| evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[ | |
| {"field":"cost_per_lead_fb","operator":"LESS_THAN","value":(maxCPA*100).toString()}, | |
| {"field":"offsite_conversion.fb_pixel_lead","operator":"GREATER_THAN","value":"0"}, | |
| {"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"}, | |
| {"field":"time_preset","value":"TODAY","operator":"EQUAL"} | |
| ] | |
| }; | |
| execSpec = { | |
| "execution_type":"UNPAUSE", | |
| "execution_options":[ | |
| {"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"} | |
| ]}; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| name = `TurnOn All ${cbo?'Campaigns':'Adsets'} at ${hour}`; | |
| evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[{"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"},{"field":"time_preset","value":"MAXIMUM","operator":"EQUAL"}] | |
| }; | |
| execSpec = { | |
| "execution_type":"UNPAUSE", | |
| "execution_options":[ | |
| {"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"} | |
| ]}; | |
| schedSpec = { | |
| "schedule_type":"CUSTOM", | |
| "schedule":[ | |
| {"days":[0],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[1],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[2],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[3],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[4],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[5],"start_minute":hour*60,"end_minute":hour*60}, | |
| {"days":[6],"start_minute":hour*60,"end_minute":hour*60} | |
| ] | |
| }; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| let createCpcRules = confirm('Do you want to create rules based on Max CPC?'); | |
| if (createCpcRules){ | |
| let maxCPC = prompt("Enter your maximum CPC (for example 0.13):"); | |
| let maxClicks = prompt(`Enter clicks limit after which the ${cbo?'campaign':'adset'} will be shut down:`); | |
| name = `TurnOff ${cbo?'Campaign':'Adset'} With Expensive CPC`; | |
| evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[ | |
| {"field":"clicks","operator":"GREATER_THAN","value":(maxClicks).toString()}, | |
| {"field":"cpc","operator":"GREATER_THAN","value":(maxCPC*100).toString()}, | |
| {"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"}, | |
| {"field":"time_preset","value":"TODAY","operator":"EQUAL"} | |
| ]}; | |
| execSpec = { | |
| "execution_type":"PAUSE", | |
| "execution_options":[{"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"}] | |
| }; | |
| schedSpec = {"schedule_type":"SEMI_HOURLY"}; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| } | |
| let createCpmRules = confirm('Do you want to create rules based on Max CPM?'); | |
| if (createCpmRules){ | |
| let maxCPM = prompt("Enter your maximum CPM:"); | |
| let maxImpressions = prompt(`Enter your maximum impressions after which the ${cbo?'campaign':'adset'} will be shut down:`); | |
| name = `TurnOff ${cbo?'Campaign':'Adset'} With Expensive CPM`; | |
| evalSpec = { | |
| "evaluation_type":"SCHEDULE", | |
| "filters":[ | |
| {"field":"impressions","operator":"GREATER_THAN","value":maxImpressions.toString()}, | |
| {"field":"cpm","operator":"GREATER_THAN","value":(maxCPM*100).toString()}, | |
| {"field":"entity_type","value":`${cbo?'CAMPAIGN':'ADSET'}`,"operator":"EQUAL"}, | |
| {"field":"time_preset","value":"TODAY","operator":"EQUAL"} | |
| ]}; | |
| execSpec = { | |
| "execution_type":"PAUSE", | |
| "execution_options":[{"field":"alert_preferences","value":{"instant":{"trigger":"CHANGE"}},"operator":"EQUAL"}] | |
| }; | |
| schedSpec = {"schedule_type":"SEMI_HOURLY"}; | |
| await addRule(accountId, name, evalSpec, execSpec, schedSpec); | |
| } | |
| alert('All Done!'); | |
| } | |
| async function getAllRules(accountId){ | |
| let f = await fetch(`${api}/act_${accountId}/adrules_library?access_token=${__accessToken}`, { | |
| "headers": headers, | |
| "referrer": "https://business.facebook.com/", | |
| "referrerPolicy": "origin-when-cross-origin", | |
| "body": null, | |
| "method": "GET", | |
| "mode": "cors", | |
| "credentials": "include" | |
| }); | |
| let rules = await f.json(); | |
| return rules; | |
| } | |
| async function deleteRule(ruleId){ | |
| let f = await fetch(`${api}/${ruleId}?access_token=${__accessToken}&method=delete`, { | |
| "headers": headers, | |
| "referrer": "https://business.facebook.com/", | |
| "referrerPolicy": "origin-when-cross-origin", | |
| "body": "method=delete", | |
| "method": "POST", | |
| "mode": "cors", | |
| "credentials": "include" | |
| }); | |
| let js = await f.json(); | |
| console.log(js); | |
| } | |
| async function clearRules(accountId){ | |
| let rules = await getAllRules(accountId); | |
| let rulesCount = rules.data.length; | |
| if (rulesCount==0) return; | |
| let clear = confirm(`Do you want to clear all existing autorules (${rulesCount} found)?`); | |
| if (!clear) return; | |
| console.log(`Deleting ${rulesCount} rules.`); | |
| for (const rule of rules.data) { | |
| console.log(`Deleting rule ${JSON.stringify(rule)}...`); | |
| await deleteRule(rule['id']); | |
| }; | |
| } | |
| async function addRule(accountId, name, evalSpec, execSpec, schedSpec){ | |
| let body = { | |
| "locale":"en_US", | |
| "evaluation_spec":JSON.stringify(evalSpec), | |
| "execution_spec":JSON.stringify(execSpec), | |
| "name":name, | |
| "schedule_spec":JSON.stringify(schedSpec), | |
| "access_token":__accessToken, | |
| "status":"ENABLED" | |
| }; | |
| let f = await fetch(`${api}/act_${accountId}/adrules_library?access_token=${__accessToken}`, { | |
| "headers": headers, | |
| "referrer": "https://business.facebook.com/", | |
| "referrerPolicy": "origin-when-cross-origin", | |
| "body": new URLSearchParams(body).toString(), | |
| "method": "POST", | |
| "mode": "cors", | |
| "credentials": "include" | |
| }); | |
| let json = await f.json(); | |
| console.log(`${name}: ${JSON.stringify(json)}`); | |
| return json; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What exactly doesnt' work?