Facebook Offline Convertions

30 Views Asked by At

The Offline Conversions API stopped working from Graph API version v17 onwards. Now, the Conversions API accepts both Online and Offline data.

I am trying to adapt to these changes but am facing some issues during development. Below is the code for a better understanding of the case:

Imports

from facebook_business.api import FacebookAdsApi
from facebook_business.adobjects.business import Business
from facebook_business.adobjects.adaccount import AdAccount
import json
import hashlib
from datetime import date
import boto3
from datetime import datetime
from pyspark.sql.functions import sha2, lower, trim, regexp_replace, translate
import re
import requests
import time

Establishing a session with AWS Secrets Manager to retrieve Facebook credentials.

session = boto3.session.Session()
client = session.client(
    service_name='secretsmanager',
    region_name='random-region'
)
response = client.get_secret_value(
    SecretId='mysecret'
)
database_secrets = json.loads(response['SecretString'])
app_id = (database_secrets['app_id'])
app_secret= (database_secrets['app_secret'])
access_token = (database_secrets['access_token'])

FacebookAdsApi.init(app_id=app_id, app_secret=app_secret, access_token=access_token)

business_id = 'my_businnes_id'
business = Business(business_id)

ad_accounts = business.get_owned_ad_accounts(fields=['id','name'])

Query Delta Table

query = spark.sql("SELECT * FROM My_Query")

df = query

Hashing certain fields for privacy compliance

hashed_df = df.selectExpr(
    "event_time",
    "event_name",
    "replace(value, ',', '.') as value",
    "currency",
    "data_processing_options",
    "sha2(trim(lower(email)), 256) as em",
    "sha2(ltrim(regexp_replace(phone, '[^0-9]', ''), '0'), 256) as ph",
    "sha2(trim(lower(fn)), 256) as fn", 
    "sha2(trim(lower(ln)), 256) as ln",
    "sha2(regexp_replace(trim(dt_nascimento), '[^a-zA-Z0-9]', ''), 256) as db",
    "sha2(regexp_replace(translate(trim(lower(cidade)), 'áãâéêíóôõúÁÃÂÉÊÍÓÔÕÚ', 'aaaeeiooouAAAEEIOOOU'), ' ', ''), 256) as ct",
    "sha2(regexp_replace(CAST(venda_ido AS STRING), '[^a-zA-Z0-9]', ''), 256) as order_id",
    "sha2(regexp_replace(sku, '[^a-zA-Z0-9]', ''), 256) as item_code",
    "sha2(regexp_replace(trim(lower(grupo_produto)), '[^a-zA-Z0-9]', ''), 256) as grupo_produto",
    "sha2(regexp_replace(trim(lower(subcategoria)), '[^a-zA-Z0-9]', ''), 256) as subcategoria",
    "sha2(regexp_replace(trim(lower(nm_segmento)), '[^a-zA-Z0-9]', ''), 256) as nm_segmento",
    "store_code"
)

Defining a function to extract the store code from the account name

def extract_store_code(account_name):
    match = re.search(r'^(\d+)\s', account_name)
    return match.group(1) if match else None

Sending Data to Facebook

max_retries = 150
wait_seconds = 10

for ad_account in ad_accounts:
    ad_account_id = ad_account['id']
    ad_account_name = ad_account['name']
    store_code = extract_store_code(ad_account_name)

    relevant_events = [event for event in events_data if event['store_code'] == store_code]

    if not relevant_events:
        print(f"None {ad_account_id} (Store: {store_code})")
        continue

    account = AdAccount(ad_account_id)

    for event in relevant_events:
        attempt = 0
        while attempt < max_retries:
            try:
                event_data = {
                    "event_name": event['event_name'],
                    "event_time": event['event_time'],
                    "action_source": "offline",
                    "event_source_url": "http://www.mysite.com.br",
                    "user_data": {
                        "em": event['em'],
                        "ph": event['ph'],
                        "fn": event['fn'],
                        "ln": event['ln'],
                        "db": event['db'],
                        "ct": event['ct']
                    },
                    "custom_data": {
                        "value": event['value'],
                        "currency": event['currency'],
                        "order_id": event['order_id'],
                        "item_code": event['item_code'],
                        "grupo_produto": event['grupo_produto'],
                        "subcategoria": event['subcategoria'],
                        "nm_segmento": event['nm_segmento']
                    }
                }

                params = {
                    'data': [event_data],
                    'access_token': access_token
                }

                response = account.create_event(params=params)
                if response and 'success' in response and response.get('success'):
                    print(f"Event sended to {ad_account_id}.")
                    break  
                else:
                    print(f"Error {ad_account_id}: {response}")
                attempt += 1  
            except Exception as e:
                attempt += 1
                if attempt < max_retries:
                    print(f"Waiting {wait_seconds} seconds...")
                    time.sleep(wait_seconds)

Errors:

Error: Exception on attempt 1 to send event to account act_000000myID: 'AdAccount' object has no attribute 'create_event''

I tried this method:


max_retries = 150
wait_seconds = 10
base_url = 'https://graph.facebook.com/v19.0'

for ad_account in ad_accounts:
    ad_account_id = ad_account['id']
    ad_account_name = ad_account['name']

    # Filters relevant events for the current account based on 'store_code'
    relevant_events = [event for event in events_data if str(event['store_code']) == extract_store_code(ad_account_name)]

    if not relevant_events:
        print(f"No relevant event for the account {ad_account_id} (Store: {extract_store_code(ad_account_name)})")
        continue

    url = f'{base_url}/{ad_account_id}/events'

    for event in relevant_events:
        attempt = 0
        while attempt < max_retries:
            try:
                # Preparing the event payload according to the API structure
                event_payload = {
                    'data': [event],
                    'access_token': access_token
                }

                response = requests.post(url, json=event_payload)
                response_data = response.json()

                if response.status_code == 200 and 'success' in response_data and response_data['success']:
                    print(f"Event successfully sent to the account {ad_account_id}.")
                    break
                else:
                    print(f"Error sending event to the account {ad_account_id}: {response_data}")
                    attempt += 1
            except Exception as e:
                print(f"Exception on attempt {attempt + 1} to send event to the account {ad_account_id}: {e}")
                attempt += 1
                if attempt < max_retries:
                    print(f"Waiting {wait_seconds} seconds before trying again...")
                    time.sleep(wait_seconds)

Error:

Error sending event to the account act_000000myID: {'error': {'message': "Unsupported post request. Object with ID 'act_000000myID' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api", 'type': 'GraphMethodException', 'code': 100, 'error_subcode': 33, 'fbtrace_id': 'AhbJaI_6XiSAvZu9w3c7hsC'}}

My Token have this permitions:

manage_fundraisers read_insights catalog_management ads_management ads_read business_management email pages_show_list instagram_basic instagram_manage_comments instagram_content_publish pages_read_engagement pages_manage_metadata pages_manage_posts

0

There are 0 best solutions below