Facebook Ads Automated Changelog
This automation will help you track the changes you make in Business Manager.
This automation allows you to export the following activities into a Spreadsheet:
- updated ad status
- updated adset status
- updated campaign status
- updated adset budget
- updated campaign budget
- ad set bidding updated
- updated status of ad after it finishes ad review
- updated ad creative
- ad set bid strategy updated
- ad set bid adjustments updated
- ad set targeting updated
- ad not approved
- ad created
- ad set created
- campaign created
JSON Recipe
Import the automation recipe(s) into your own account. Don’t know how? Learn here.
{"name":"Facebook Changelog","description":"facebook_ads_change_log_sheets_20220530","nodes":{"process_script_1":{"type":"process_script","logging_enabled":false,"error_rules":[],"x":732,"y":137,"group":"group_1","inputs":{"src":{"export_enabled":true,"data":"activities = inputs[\"a\"]\nevents_to_include = inputs[\"b\"]\n\nfrom datetime import datetime\nimport json\n\n# Define a dictionary to map old names to new names\nold_names = {\n 'CAMPAIGN_GROUP': 'Campaign',\n 'CAMPAIGN': 'Adset',\n 'ADGROUP': 'Ad',\n 'ACCOUNT': 'Account'\n}\n\n# Initialize a list to store the log items\nactivity_log = []\n\n# Process each activity\nfor activity in activities:\n log_item = {}\n\n # Extract date and time and convert it to ISO format\n date_time = activity.get('date_time_in_timezone', '').replace(\"at \", \"\").replace(\"um \", \"\").replace(\" Uhr\", \"\")\n if \"pm\" in date_time.lower() or \"am\" in date_time.lower():\n iso_time = datetime.strptime(date_time, \"%m/%d/%Y %I:%M %p\").isoformat()\n elif \".\" in date_time.lower():\n iso_time = datetime.strptime(date_time, \"%d.%m.%Y %H:%M\").isoformat()\n else:\n iso_time = datetime.strptime(date_time, \"%d/%m/%Y %H:%M\").isoformat()\n\n log_item[\"account_id\"] = activity.get('account_id', '')\n log_item[\"provider\"] = activity.get('provider', '')\n log_item[\"actor_name\"] = activity.get('actor_name', '')\n log_item[\"event_time\"] = iso_time\n log_item[\"object_type\"] = old_names.get(activity.get('object_type', ''), '')\n log_item[\"object_name\"] = activity.get('object_name', '')\n log_item[\"event_type\"] = activity.get('event_type', '')\n log_item[\"translated_event_type\"] = activity.get('translated_event_type', '')\n log_item[\"campaign_name\"] = activity.get('campaign_name', '')\n \n # Fetch deeplinks\n object_id = activity.get('object_id', '')\n object_type = log_item[\"object_type\"]\n account_id = log_item['account_id']\n \n if object_type == \"Campaign\":\n log_item[\"deeplink\"] = f\"https://business.facebook.com/adsmanager/manage/campaigns?act={account_id}\u0026filter_set=SEARCH_BY_CAMPAIGN_GROUP_IDS-STRING_%1EANY%1E[{object_id}]\u0026selected_campaign_ids={object_id}\"\n elif object_type == \"Adset\":\n log_item[\"deeplink\"] = f\"https://business.facebook.com/adsmanager/manage/adsets?act={account_id}\u0026filter_set=SEARCH_BY_CAMPAIGN_IDS-STRING_%1EANY%1E[{object_id}]\u0026selected_adset_ids={object_id}\"\n elif object_type == \"Ad\":\n log_item[\"deeplink\"] = f\"https://business.facebook.com/adsmanager/manage/ads?act={account_id}\u0026filter_set=SEARCH_BY_AD_GROUP_IDS-STRING_%1EANY%1E[{object_id}]\u0026selected_ad_ids={object_id}\"\n \n # Retrieve the 'application_name' from activities (as you initially had it)\n application_name = activity.get('application_name', '')\n\n # Check if 'application_name' is empty, and set it to \"Meta\" in that case\n if not application_name:\n application_name = \"Meta\"\n\n log_item[\"application_name\"] = application_name\n log_item[\"extra_data\"] = activity.get('extra_data', '')\n\n event_type = activity.get('event_type', '')\n\n if event_type in [\"update_ad_run_status\", \"update_ad_set_run_status\"]:\n extra_data = json.loads(activity['extra_data'])\n activity[\"extra_data\"] = extra_data\n old_value = extra_data.get('old_value', '')\n new_value = extra_data.get('new_value', '')\n log_item[\"old_value\"] = old_value\n log_item[\"new_value\"] = new_value\n log_item[\"ad_campaign_id\"] = extra_data.get('campaign_id', '')\n\n # Check if 'comment' exists in extra_data, and provide an empty string if it doesn't\n log_item[\"comment\"] = extra_data.get('comment', '')\n \n elif event_type == \"update_ad_set_bid_adjustments\":\n # Correctly process extra_data for bid adjustments\n extra_data_str = activity['extra_data'].replace('\"{', '{').replace('}\"', '}').replace('\\\\\"', '\"')\n extra_data = json.loads(extra_data_str)\n\n # Initialize message parts\n old_value_parts = []\n new_value_parts = []\n \n # Extract old_value and new_value from extra_data\n old_value = extra_data.get('old_value', {})\n new_value = extra_data.get('new_value', {})\n \n # Process old_value\n if isinstance(old_value, dict):\n for key, value in old_value.items():\n if isinstance(value, dict):\n for subkey, subvalue in value.items():\n if isinstance(subvalue, dict):\n for inner_key, inner_value in subvalue.items():\n old_value_parts.append(f\"{key} {subkey} {inner_key}: {inner_value}\")\n else:\n old_value_parts.append(f\"{key} {subkey}: {subvalue}\")\n else:\n old_value_parts.append(f\"{key}: {value}\")\n \n # Process new_value\n if isinstance(new_value, dict):\n for key, value in new_value.items():\n if isinstance(value, dict):\n for subkey, subvalue in value.items():\n if isinstance(subvalue, dict):\n for inner_key, inner_value in subvalue.items():\n new_value_parts.append(f\"{key} {subkey} {inner_key}: {inner_value}\")\n else:\n new_value_parts.append(f\"{key} {subkey}: {subvalue}\")\n else:\n new_value_parts.append(f\"{key}: {value}\")\n \n # Construct the message\n old_value_str = ', '.join(old_value_parts)\n new_value_str = ', '.join(new_value_parts)\n bid_type = extra_data.get('type', 'bid adjustment')\n if old_value_parts:\n message = f\"Made bid adjustments to {bid_type} from {old_value_str} to {new_value_str}.\"\n else:\n message = f\"Made bid adjustments to {bid_type}: Added {new_value_str}.\"\n \n log_item[\"comment\"] = message\n # Add the log item to the activity log\n activity_log.append(log_item)\n\n# Assign the 'activity_log' to the outputs\noutputs[\"a\"] = activity_log"},"b":{"title":"events_to_include","description":"Any data that is sent to the remote function"},"a":{"title":"activities","description":"Any data that is sent to the remote function"},"runtime":{"export_enabled":true,"data":"python3_7"}},"outputs":{"processed":{"title":"done","description":"Triggered when processing is done"},"a":{"title":"a: activity_log","description":"Data from response.outputs.a"}}},"stop_1":{"type":"stop","logging_enabled":false,"error_rules":[],"x":1659,"y":249},"start_1":{"type":"start","logging_enabled":false,"error_rules":[],"x":11,"y":514},"fb_select_ad_account_ids_v2_1":{"type":"fb_select_ad_account_ids_v2","logging_enabled":false,"error_rules":[],"x":135,"y":305,"group":"group_2","inputs":{"ad_account_ids":{"title":"ad_account_ids","description":"Select one or more Facebook Accounts"}}},"delay_to_1":{"type":"delay_to","logging_enabled":false,"error_rules":[],"x":206,"y":443,"inputs":{"weekdays":{"export_enabled":true,"data":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]},"time":{"export_enabled":true,"data":"03:00:00-08:00"}}},"fb_fetch_activities_v3_1":{"type":"fb_fetch_activities_v3","logging_enabled":false,"error_rules":[],"x":678,"y":204,"group":"group_2"},"input_strings_v2_1":{"type":"input_strings_v2","logging_enabled":false,"error_rules":[],"x":300,"y":122,"group":"group_1","inputs":{"strings":{"title":"Select actions for reporting","description":"The strings to input","export_enabled":true,"data":["update_campaign_budget","update_ad_set_budget","update_ad_run_status","update_ad_set_run_status","update_campaign_run_status","update_ad_run_status_to_be_set_after_review","update_ad_set_bidding","update_ad_set_bid_adjustments","update_ad_set_bid_strategy","update_ad_set_target_spec","create_ad_set","create_campaign_group","ad_review_declined","create_ad","application_name","update_ad_creative"]}},"outputs":{"strings":{"title":"activity_types_selected","description":"The strings to input"}}},"map_any_to_table_rows_1":{"type":"map_any_to_table_rows","logging_enabled":false,"error_rules":[],"x":427,"y":368,"group":"group_3","inputs":{"add_header":{"export_enabled":true,"data":true},"mapping":{"export_enabled":true,"data":{"A":"/provider","B":"/account_id","C":"/translated_event_type","D":"/object_type","E":"/object_name","F":"/event_time","G":"/old_value","H":"/new_value","I":"/currency","J":"/actor_name","K":"/comment","L":"/campaign_name","M":"/deeplink","N":"/application_name"}},"schema":{"export_enabled":true,"data":"any_list"}}},"google_sheets_select_spreadsheet_id_v2_1":{"type":"google_sheets_select_spreadsheet_id_v2","logging_enabled":false,"error_rules":[],"x":437,"y":125,"group":"group_3","inputs":{"range":{"title":"range","description":"The range in A1 notation to fetch"},"spreadsheet_id":{"title":"spreadsheet_id","description":"The spreadsheet to fetch from"}}},"google_sheets_append_table_rows_v3_1":{"type":"google_sheets_append_table_rows_v3","logging_enabled":false,"error_rules":[],"x":791,"y":300,"group":"group_3","outputs":{"appended":{"title":"appended","description":"Triggered when appended"}}},"input_any_1":{"type":"input_any","logging_enabled":false,"error_rules":[],"x":385,"y":501,"group":"group_2"},"select_date_range_1":{"type":"select_date_range","logging_enabled":false,"error_rules":[],"x":91,"y":504,"group":"group_2","inputs":{"date_range":{"export_enabled":true,"data":"yesterday"}}},"fb_fetch_insights_v6_1":{"type":"fb_fetch_insights_v6","logging_enabled":false,"error_rules":[],"x":980,"y":371,"group":"group_2","inputs":{"action_report_time":{"export_enabled":true,"data":"conversion"},"breakdowns":{"export_enabled":true},"action_breakdowns":{"export_enabled":true},"fields":{"export_enabled":true,"data":["account_id","account_name","campaign_id","campaign_name","adset_id","adset_name","ad_id","ad_name"]},"use_unified_attribution_setting":{"export_enabled":true,"data":true},"level":{"export_enabled":true,"data":"ad"},"action_attribution_windows":{"export_enabled":true,"data":["default"]},"time_increment":{"export_enabled":true,"data":"all_days"}}},"filter_v2_1":{"type":"filter_v2","logging_enabled":false,"error_rules":[],"x":1051,"y":165,"inputs":{"filters":{"export_enabled":true,"data":[{"operator":"=","pointer":"/translated_event_type","value":"Ad set bid adjustments updated"}]}}},"split_list_1":{"type":"split_list","logging_enabled":false,"error_rules":[],"x":1268,"y":414,"group":"group_2","inputs":{"size":{"export_enabled":true,"data":200}}},"for_each_v2_1":{"type":"for_each_v2","logging_enabled":false,"error_rules":[],"x":1583,"y":418,"group":"group_2"},"process_script_2":{"type":"process_script","title":"Enrich data","description":"Processes a script and maps responses to the outputs","logging_enabled":false,"max_job_retries":2,"timeout":90,"error_rules":[],"x":1853,"y":406,"group":"group_2","inputs":{"src":{"export_enabled":true,"data":"activities = inputs.get('a', [])\ninsights = inputs.get('b', [])\n\nfor activity in activities: \n for insight in insights:\n if activity.get('object_type'):\n campaign_name = insight['campaign_name']\n campaign_id = insight['campaign_id']\n adset_name = insight['adset_name']\n adset_id = insight['adset_id']\n ad_id = insight['ad_id']\n object_type = activity['object_type']\n object_id = activity['object_id']\n \n if object_type in ['CAMPAIGN_GROUP', 'CAMPAIGN', 'ADGROUP'] and object_id in [campaign_id, adset_id, ad_id]:\n activity['campaign_name'] = campaign_name\n activity['campaign_id'] = campaign_id\n \n if object_type in ['CAMPAIGN', 'ADGROUP'] and object_id in [adset_id, ad_id]:\n activity['adset_name'] = adset_name\n activity['adset_id'] = adset_id\n\noutputs['a'] = activities \n "},"runtime":{"export_enabled":true,"data":"python3_7"}},"outputs":{"a":{"title":"a: activities","description":"Data from response.outputs.a"}}},"append_1":{"type":"append","logging_enabled":false,"error_rules":[],"x":2153,"y":441,"group":"group_2","inputs":{"flatten":{"export_enabled":true,"data":true},"schema":{"export_enabled":true,"data":"any"}}}},"edges":[{"id":"for_each_v2_1.item:process_script_2.a","points":[]},{"id":"split_list_1.list_of_lists:for_each_v2_1.items","points":[]},{"id":"for_each_v2_1.do:process_script_2.process","points":[]},{"id":"process_script_2.processed:append_1.append","points":[]},{"id":"process_script_2.a:append_1.item","points":[]},{"id":"append_1.appended:for_each_v2_1.next","points":[]},{"id":"split_list_1.split:append_1.reset","points":[]},{"id":"append_1.resetted:for_each_v2_1.start","points":[]},{"id":"fb_fetch_activities_v3_1.activities:split_list_1.data_list","points":[]},{"id":"fb_fetch_insights_v6_1.insights:process_script_2.b","points":[]},{"id":"append_1.list:process_script_1.a","points":[]},{"id":"fb_fetch_insights_v6_1.fetched:split_list_1.split","points":[]},{"id":"for_each_v2_1.done:process_script_1.process","points":[]},{"id":"process_script_1.a:filter_v2_1.items","points":[]},{"id":"filter_v2_1.items:map_any_to_table_rows_1.data","points":[]},{"id":"start_1.start:delay_to_1.start","points":[]},{"id":"input_any_1.any:fb_fetch_activities_v3_1.date_preset","points":[]},{"id":"select_date_range_1.date_range:input_any_1.any","points":[]},{"id":"input_any_1.any:fb_fetch_insights_v6_1.date_range","points":[]},{"id":"google_sheets_select_spreadsheet_id_v2_1.spreadsheet_id:google_sheets_append_table_rows_v3_1.spreadsheet_id","points":[]},{"id":"google_sheets_select_spreadsheet_id_v2_1.range:google_sheets_append_table_rows_v3_1.range","points":[]},{"id":"map_any_to_table_rows_1.mapped:google_sheets_append_table_rows_v3_1.append","points":[]},{"id":"map_any_to_table_rows_1.rows:google_sheets_append_table_rows_v3_1.rows","points":[]},{"id":"google_sheets_append_table_rows_v3_1.appended:delay_to_1.start","points":[]},{"id":"fb_select_ad_account_ids_v2_1.ad_account_ids:fb_fetch_insights_v6_1.ad_account_ids","points":[]},{"id":"fb_select_ad_account_ids_v2_1.ad_account_ids:fb_fetch_activities_v3_1.ad_account_ids","points":[]},{"id":"fb_fetch_activities_v3_1.fetched:fb_fetch_insights_v6_1.fetch","points":[]},{"id":"delay_to_1.delayed:fb_fetch_activities_v3_1.fetch","points":[]},{"id":"input_strings_v2_1.strings:process_script_1.b","points":[]},{"id":"process_script_1.processed:filter_v2_1.filter","points":[]},{"id":"filter_v2_1.filtered:map_any_to_table_rows_1.map","points":[]}],"groups":{"group_2":{"title":"Get All Activities from Facebook","description":"","x":459,"y":198,"inputs":["fb_fetch_activities_v3_1.fetch"],"outputs":["append_1.list","for_each_v2_1.done"]},"group_3":{"title":"Add to Spreadsheet","description":"","x":1341,"y":239,"inputs":["map_any_to_table_rows_1.data","map_any_to_table_rows_1.map"],"outputs":["google_sheets_append_table_rows_v3_1.appended"]},"group_1":{"title":"Build Log","description":"","x":745,"y":201,"inputs":["process_script_1.process","process_script_1.a"],"outputs":["process_script_1.a","process_script_1.processed"]}},"widgets":{"widget_1":{"title":"Date Range","description":"Choose a date preset (custom date ranges are not supported for change log)","position":0,"icon":"las la-calendar","input":"select_date_range_1.date_range"},"widget_2":{"title":"Facebook Account","description":"Select one or more Facebook Accounts","position":0,"input":"fb_select_ad_account_ids_v2_1.ad_account_ids"},"widget_3":{"title":"Weekdays","description":"The weekdays to delay the trigger","position":5,"input":"delay_to_1.weekdays"},"widget_4":{"title":"Time","description":"The time to delay the trigger","position":6,"input":"delay_to_1.time"},"widget_5":{"title":"Spreadsheet","description":"The spreadsheet to push data into.","position":1,"input":"google_sheets_select_spreadsheet_id_v2_1.spreadsheet_id"},"widget_6":{"title":"Tab","description":"A tab or range in A1 notation.","position":2,"icon":"las la-table","input":"google_sheets_select_spreadsheet_id_v2_1.range"},"widget_7":{"title":"Select activity types","description":"Select actions to report to\n\n\n","position":3,"options":[{"data":"update_ad_run_status","title":"Updated ad status"},{"data":"update_ad_set_run_status","title":"Updated adset status"},{"data":"update_ad_set_budget","title":"Updated adset budget"},{"data":"update_campaign_budget","title":"Updated campaign budget"},{"data":"update_campaign_run_status","title":"Updated campaign status"},{"data":"update_ad_set_bidding","title":"Ad set bidding updated"},{"data":"update_ad_set_bid_strategy","title":"Ad set bid strategy updated"},{"data":"update_ad_set_bid_adjustments","title":"Ad set bid adjustments updated"},{"data":"update_ad_set_target_spec","title":"Ad set targeting updated"},{"data":"create_campaign_group","title":"Campaign created"},{"data":"ad_review_declined","title":"Ad not approved"},{"data":"update_ad_run_status_to_be_set_after_review","title":"Updated status of ad after review"},{"data":"create_ad_set","title":"Adset created"},{"data":"create_ad","title":"Ad created"},{"data":"update_ad_creative","title":"Creative edited"}],"input":"input_strings_v2_1.strings"}},"variables":{},"config":{"capture_inputs_enabled":false,"caching_enabled":false},"tags":[]}
How To
Step 1
GSheets
Create a new spreadsheet.
Step 2
- Select a Speadsheet and tab that you have created in the step 1. If it doesn’t show up, hit thre refresh icon 🔄.
- Select a Facebook Ad Account
- Select the activity types on which you would like to report. You need to select at least 1 action
- Optionally, choose on which weekdays you want to run the automation. Note that per default only yesterday’s change log is added.
- Choose at what time you want to run the automation. It is recommended to run early in the morning to capture yesterday’s changes.
- Click Run Automation
The automation will now get yesterday’s change log and add it to the spreadsheet and then wait until the specified time and weekday to run again.
Did this answer your question?
😞
😐
🤩
Last updated on February 23, 2024