適用於轉換 API 的 Meta 商業 SDK 功能

本指南旨在協助您運用專為轉換 API 用戶設計的 Meta 商業 SDK 進階功能。非同步要求並行批次處理HTTP 服務介面可用於 PHP、NodeJS、Java、Python 和 Ruby SDK。若要瞭解基本的轉換 API 用法,請參閱主要轉換 API 說明文件

Meta 商業 SDK 可讓您存取我們的商業 API 套件,以建置專屬和客製化的解決方案,為您的企業和客戶提供服務。轉換 API 就是可供 SDK 用戶使用的 API 之一。

必備條件

您必須先安裝 Meta 商業 SDK,才能使用下列任一功能。請參閱 Meta 商業 SDK 新手指南,或按照下列 README 指示操作:

使用這些功能所需的最低語言版本:

  • PHP >= 7.2
  • Node.js >= 7.6.0
  • Java >= 8
  • Python >= 2.7
  • Ruby >= 2

非同步要求

如果您不想阻擋程式執行以等待要求完成,可以使用此功能。此方法可讓您發出要求,並在要求完成後取得伺服器傳回的訊號。等待回應時,程式可以繼續執行。

非同步要求可讓您更有效運用資源,進而縮短伺服器回應時間。此外,您也能進一步控制程式如何處理伺服器傳回的錯誤,並可輕鬆將 SDK 整合至已非同步執行的程式碼中。

若要實作非同步要求,請參閱下列語言的程式碼範例:

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\UserData;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

Api::init(null, null, $access_token, false);

function create_events($num) {
  $user_data = (new UserData())
    ->setEmail('joe' . $num . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  $event = (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/123')
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);

  return array($event);
}

function create_async_request($pixel_id, $num) {
  $async_request = (new EventRequestAsync($pixel_id))
    ->setEvents(create_events($num));
  return $async_request->execute()
    ->then(
      null,
      function (RequestException $e) {
        print(
          "Error!!!\n" .
          $e->getMessage() . "\n" .
          $e->getRequest()->getMethod() . "\n"
        );
      }
    );
}


// Async request:
$promise = create_async_request($pixel_id, 2);

print("Request 1 state: " . $promise->getState() . "\n");
print("Async request - OK.\n");


// Async request with wait:
$promise = create_async_request($pixel_id, 3);

$response2 = $promise->wait();
print("Request 2: " . $response2->getBody() . "\n");
print("Async request with wait - OK.\n");


// Multiple async requests:
$promises = [
  "Request 3" => create_async_request($pixel_id, 4),
  "Request 4" => create_async_request($pixel_id, 5),
];

$response3 = Promise\unwrap($promises);
foreach ($response3 as $request_name => $response) {
  print($request_name . ": " . $response->getBody()."\n");
}
print("Async - Multiple async requests OK.\n");
import asyncio
import time
import pprint
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request import EventRequest
from facebook_business.adobjects.serverside.event_request_async import EventRequestAsync
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def create_events(num):
    user_data = UserData(
        email="joe%s@eg.com" % num,
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    return [event]

async def execute_async_request(pixel_id, num):
    event_request_async = EventRequestAsync(
        events=create_events(num),
        pixel_id=pixel_id
    )
    return await event_request_async.execute()

async def run_tasks(pixel_id):
    tasks = []
    for i in range(1,3):
        tasks.append(execute_async_request(pixel_id, i))

    completed = await asyncio.gather(*tasks)
    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(completed)

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))
    FacebookAdsApi.init(access_token=access_token, crash_log=False)

    asyncio.run(run_tasks(pixel_id))
    print("Create EventRequest Async - OK.")
const bizSdk = require('facebook-nodejs-business-sdk');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;
void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const api = bizSdk.FacebookAdsApi.init(access_token);

    let current_timestamp = Math.floor(new Date() / 1000);

    const userData1 = (new UserData())
      .setEmail('joe1@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData1 = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent1 = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(userData1)
      .setCustomData(customData1)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventRequest1 = (new EventRequest(access_token, pixel_id))
      .setEvents([serverEvent1]);

    const userData2 = (new UserData())
      .setEmail('joe2@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData2 = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent2 = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(userData2)
      .setCustomData(customData2)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventRequest2 = (new EventRequest(access_token, pixel_id))
      .setEvents([serverEvent2]);

    Promise.all([
      eventRequest1.execute(),
      eventRequest2.execute()
    ]).then(response => {
      console.log('Execute 2 Requests OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.Event;
import com.facebook.ads.sdk.serverside.EventRequest;
import com.facebook.ads.sdk.serverside.EventResponse;
import com.facebook.ads.sdk.serverside.UserData;
import com.facebook.ads.sdk.serverside.CustomData;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class CONVERSIONS_API_EVENT_CREATE_ASYNC {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  private static EventRequest getEventRequest(APIContext context, int num) {
    UserData userData = new UserData()
      .email(String.format("joe%s@eg.com", num))
      .clientIpAddress(clientIpAddress)
      .clientUserAgent(clientUserAgent);

    HashMap<String,String> customProperties = new HashMap<>();
    customProperties.put("custom1", "value2");

    CustomData customData = new CustomData()
      .currency("usd")
      .customProperties(customProperties)
      .value(123.45F);

    Event pageViewEvent = new Event();
    pageViewEvent.eventName("Purchase")
      .eventTime(System.currentTimeMillis() / 1000L)
      .userData(userData)
      .customData(customData)
      .eventSourceUrl("http://jaspers-market.com/product/123")
      .actionSource(ActionSource.website);

    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(pageViewEvent);

    return eventRequest;
  }

  private static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }
    APIContext context = new APIContext(ACCESS_TOKEN);
    context.setLogger(System.out);

    EventRequest asyncRequest = getEventRequest(context, 1);
    final ListenableFuture<EventResponse> requestFuture = asyncRequest.executeAsync();
    EventResponse asyncResponse = requestFuture.get();
    System.out.println(String.format("Async Request - OK: %s", asyncResponse));

    List<ListenableFuture<EventResponse>> eventFutures = new ArrayList<>();
    eventFutures.add(getEventRequest(context, 2).executeAsync());
    eventFutures.add(getEventRequest(context, 3).executeAsync());
    eventFutures.add(getEventRequest(context, 4).executeAsync());
    List<EventResponse>
require 'concurrent'
require 'facebook_ads'
require 'pp'

ACCESS_TOKEN = ENV['ACCESS_TOKEN']
PIXEL_ID = ENV['PIXEL_ID']
unless ACCESS_TOKEN && PIXEL_ID
    raise Exception.new("Missing required test config. Got pixel_id: '#{PIXEL_ID}', access_token: '#{ACCESS_TOKEN}'")
end

FacebookAds.configure do |config|
    config.access_token = ACCESS_TOKEN
end

def get_events(num)
    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe#{num}@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    event = FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )

    [event]
end

def get_event_request_async(num)
    FacebookAds::ServerSide::EventRequestAsync.new(
        pixel_id: PIXEL_ID,
        events: get_events(num)
    )
end

def main
    request = get_event_request_async(1)
    response = request.execute.value!
    print "Response: #{response}\n"
    print "EventRequest async single - OK.\n"

    promises = (2..3).map {|num| get_event_request_async(num).execute }
    responses = Concurrent::Promise.zip(*promises)
        .execute
        .value!
    print "Responses:\n"
    pp responses
    print "EventRequest async multi - OK.\n"
end

main

並行批次處理

並行批次處理運用非同步要求,能夠更有效地利用資源,進而提高傳輸量。您可以建立批次要求來支援事件要求工作者、cron job(排程工作)等使用案例。

您有下列 BatchProcessor 方法可以選擇:

方法使用時機

processEvents

此方法可用來處理具有相同最上層 EventRequest 欄位(例如 namespace_idupload_tag)的事件。

processEventsGenerator

這是 processEvents 的基底產生器。


此方法也可以用來處理具有相同最上層 EventRequest 欄位(例如 namespace_idupload_tag)的事件。

processEventRequests

當您想要為每個要求指定不同的 EventRequest 欄位時,可以使用此方法來並行處理 EventRequests

processEventRequestsGenerator

這是 processEventRequests 的基底產生器。


當您想要為每個要求指定不同的 EventRequest 欄位時,也可以使用此方法來並行處理 EventRequests

使用並行批次處理時,應盡可能即時傳送事件。如需詳細資訊,請參閱分享頻率

如果您使用 PHP、Python 或 Ruby SDK,則上述方法需要 EventRequestAsync 物件,而不是 EventRequest。

若要實作並行批次處理,請參閱下列語言的程式碼範例:

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\BatchProcessor;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\UserData;

use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

$api = Api::init(null, null, $access_token, false);

function create_event($i) {
  $user_data = (new UserData())
    ->setEmail('joe' . $i . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  return (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/' . $i)
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);
}

function create_events($num) {
  $events = [];

  for ($i = 0; $i < $num; $i++) {
    $events[] = create_event($i);
  }

  return $events;
}

function create_async_requests($pixel_id, $num) {
  $requests = [];

  for ($i = 0; $i < $num; $i++) {
    $requests[] = (new EventRequestAsync($pixel_id))
      ->setUploadTag('test-tag-2')
      ->setEvents([create_event($i)]);
  }

  return $requests;
}

function run($pixel_id) {
  print("Started CONVERSIONS_API_EVENT_CREATE_BATCH...\n");
  $batch_processor = new BatchProcessor($pixel_id, 2, 2);

  // processEvents
  $events = create_events(11);
  $batch_processor->processEvents(array('upload_tag' => 'test-tag-1'), $events);

  // processEventRequests
  $requests = create_async_requests($pixel_id, 5);
  $batch_processor->processEventRequests($requests);

  // processEventsGenerator
  $process_events_generator = $batch_processor->processEventsGenerator(array('upload_tag' => 'test-tag-1'), $events);
  foreach ($process_events_generator as $promises) {
    try {
      Promise\unwrap($promises);
    } catch (RequestException $e) {
      print('RequestException: ' . $e->getResponse()->getBody()->getContents() . "\n");
      throw $e;
    } catch (\Exception $e) {
      print("Exception:\n");
      print_r($e);
      throw $e;
    }
  }

  // processEventRequestsGenerator
  $requests = create_async_requests($pixel_id, 5);
  $process_event_requests_generator = $batch_processor->processEventRequestsGenerator($requests);
  foreach ($process_event_requests_generator as $promises) {
    try {
      Promise\unwrap($promises);
    } catch (RequestException $e) {
      print('RequestException: ' . $e->getResponse()->getBody()->getContents() . "\n");
      throw $e;
    } catch (\Exception $e) {
      print("Exception:\n");
      print_r($e);
      throw $e;
    }
  }
  print("Finished CONVERSIONS_API_EVENT_CREATE_BATCH with no errors.\n");
}

run($pixel_id);
import asyncio
import time
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.batch_processor import BatchProcessor
from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request_async import EventRequestAsync
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def get_event(num):
    user_data = UserData(
        email="joe%s@eg.com" % num,
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    return event

def get_events(num):
    events = []
    for i in range(num):
        events.append(get_event(num))
    return events

def get_event_requests_async(num):
    event_requests_async = []
    for i in range(num):
        event_requests_async.append(
            EventRequestAsync(
                events=[get_event(i)],
                pixel_id=pixel_id
            )
        )
    return event_requests_async

def run_process_event_requests():
    batch_processor = BatchProcessor(2, 2)
    event_requests_async = get_event_requests_async(3)
    batch_processor.process_event_requests(event_requests_async)

async def run_process_event_requests_generator():
    batch_processor = BatchProcessor(3, 2)
    event_requests_async = get_event_requests_async(7)
    generator = batch_processor.process_event_requests_generator(event_requests_async)
    async for batch_responses in generator:
        print(batch_responses)

def run_process_events():
    batch_processor = BatchProcessor(2, 2)
    event_request_async_to_clone = EventRequestAsync(pixel_id=pixel_id, events=[])
    events = get_events(3)
    batch_processor.process_events(event_request_async_to_clone, events)

async def run_process_events_generator():
    batch_processor = BatchProcessor(3, 2)
    event_request_async_to_clone = EventRequestAsync(pixel_id=pixel_id, events=[])
    events = get_events(10)
    generator = batch_processor.process_events_generator(event_request_async_to_clone, events)
    async for batch_responses in generator:
        print(batch_responses)

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))
    FacebookAdsApi.init(access_token=access_token, crash_log=False)

    run_process_event_requests()
    print("BatchProcessor process_event_requests - OK.")

    asyncio.run(run_process_event_requests_generator())
    print("BatchProcessor process_event_requests_generator - OK.")

    run_process_events()
    print("BatchProcessor process_events - OK.")

    asyncio.run(run_process_events_generator())
    print("BatchProcessor process_events_generator - OK.")
const bizSdk = require('facebook-nodejs-business-sdk');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;
const BatchProcessor = bizSdk.BatchProcessor;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;

function createEvents(num) {
  let events = [];
  for (let i = 0; i < num; i++) {
    let current_timestamp = Math.floor(new Date() / 1000);

    const user_data = (new UserData())
      .setEmail(`joe${i}@eg.com`)
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const custom_data = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const server_event = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(current_timestamp)
      .setUserData(user_data)
      .setCustomData(custom_data)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    events.push(server_event);
  }

  return events;
}

function createEventRequests(num, access_token, pixel_id) {
  let event_requests = [];
  for (let i = 0; i < num; i++) {
    const events = createEvents(2);
    const event_request = (new EventRequest(access_token, pixel_id))
      .setEvents(events);
    event_requests.push(event_request);
  }

  return event_requests;
}

void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const api = bizSdk.FacebookAdsApi.init(access_token);

    const batch_processor = new BatchProcessor(2, 2);

    // processEvents
    const events1 = createEvents(5);
    const event_request = (new EventRequest(access_token, pixel_id));
    batch_processor.processEvents(event_request, events1);
    console.log('BatchProcessor.processEvents - OK.');

    // processEventRequests
    const event_requests1 = createEventRequests(3, access_token, pixel_id);
    batch_processor.processEventRequests(event_requests1);
    console.log('BatchProcessor.processEventRequests - OK.');

    // processEventsGenerator
    const events2 = createEvents(5);
    const eventsGenerator = batch_processor.processEventsGenerator(event_request, events2);
    while (true) {
      const batch = eventsGenerator.next().value;
      if (!batch || batch.length === 0) {
        eventsGenerator.return();
        break;
      }

      await Promise.all(batch).then(response => {
        console.log('processEventsGenerator Events Received: ', response.map(r => r.events_received))
      }).catch(response => {
        console.log('processEventsGenerator Error: ', response);
      });
    }

    // processEventRequestsGenerator
    const event_requests2 = createEventRequests(3, access_token, pixel_id);
    const eventRequestsGenerator = batch_processor.processEventRequestsGenerator(event_requests2);
    while (true) {
      const batch = eventRequestsGenerator.next().value;
      if (!batch || batch.length === 0) {
        eventRequestsGenerator.return();
        break;
      }

      await Promise.all(batch).then(response => {
        console.log('processEventRequestsGenerator Events Received: ', response.map(r => r.events_received))
      }).catch(response => {
        console.log('processEventRequestsGenerator Error: ', response);
      });
    }
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.*;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

class CONVERSIONS_API_EVENT_CREATE_BATCH {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  public static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }

    APIContext context = new APIContext(ACCESS_TOKEN);
    context.setLogger(System.out);

    BatchProcessor batchProcessor = new BatchProcessor(2, 3);

    List
require 'concurrent'
require 'facebook_ads'

def get_event(num)
    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe#{num}@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )
end

def get_events(num)
    num.times.map do |i|
        get_event(i)
    end
end

def get_event_request_async(pixel_id, num)
    FacebookAds::ServerSide::EventRequestAsync.new(
        pixel_id: pixel_id,
        events: [get_event(num)]
    )
end

def get_event_requests_async(pixel_id, num)
    num.times.map do |i|
        get_event_request_async(pixel_id, i)
    end
end

def run_process_event_requests(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(2, 2)
    event_requests_async = get_event_requests_async(pixel_id, 3)
    batch_processor.process_event_requests(event_requests_async)
end

def run_process_event_requests_generator(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(3, 2)
    event_requests_async = get_event_requests_async(pixel_id, 7)
    generator = batch_processor.process_event_requests_generator(event_requests_async)
    generator.each do |batch|
        responses = Concurrent::Promise.zip(*batch).execute.value!
        print "#{responses}\n"
    end
end

def run_process_events(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(2, 2)
    event_request_async_to_clone = FacebookAds::ServerSide::EventRequestAsync.new(pixel_id: pixel_id)
    events = get_events(3)
    batch_processor.process_events(event_request_async_to_clone, events)
end

def run_process_events_generator(pixel_id)
    batch_processor = FacebookAds::ServerSide::BatchProcessor.new(3, 2)
    event_request_async_to_clone = FacebookAds::ServerSide::EventRequestAsync.new(pixel_id: pixel_id)
    events = get_events(10)
    generator = batch_processor.process_events_generator(event_request_async_to_clone, events)
    generator.each do |batch|
        responses = Concurrent::Promise.zip(*batch).execute.value!
        print "#{responses}\n"
    end
end

def main
    access_token = ENV['ACCESS_TOKEN']
    pixel_id = ENV['PIXEL_ID']
    unless access_token && pixel_id
        raise Exception.new("Missing required test config. Got pixel_id: '#{pixel_id}', access_token: '#{access_token}'")
    end

    FacebookAds.configure do |config|
      config.access_token = access_token
    end

    run_process_event_requests(pixel_id)
    print "BatchProcessor process_event_requests - OK.\n"

    run_process_event_requests_generator(pixel_id)
    print "BatchProcessor process_event_requests_generator - OK.\n"

    run_process_events(pixel_id)
    print "BatchProcessor process_events - OK.\n"

    run_process_events_generator(pixel_id)
    print "BatchProcessor process_events_generator - OK.\n"
end

main

HTTP 服務介面

如果您對 HTTP 服務階層有一組特定需求,請使用 HTTP 服務介面。此功能可讓您覆寫商業 SDK 的預設 HTTP 服務,並使用您偏好的方法或程式庫來實作自己的自訂服務。

若要實作自己的 HTTP 服務介面,請參閱下列語言的程式碼範例:

require __DIR__ . '/../vendor/autoload.php';

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Object\ServerSide\HttpServiceClientConfig;
use FacebookAds\Object\ServerSide\UserData;

// Imports used by the TestHttpClient class
use FacebookAds\Object\ServerSide\HttpServiceInterface;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;

$pixel_id = getenv('PIXEL_ID');
$access_token = getenv('ACCESS_TOKEN');

if (empty($pixel_id) || empty($access_token)) {
  throw new Exception('Missing required test config. Got pixel_id: "' . $pixel_id . '", access_token: "' . $access_token . '"');
}

function run($access_token, $pixel_id) {
  Api::init(null, null, $access_token, false);

  $request1 = getEventRequest($pixel_id, 1);
  $request1->setHttpClient(new TestHttpClient());

  $response1 = $request1->execute();

  print("Response: " . $response1->getBody() . "\n");
  print("Custom HTTP Service Request 1 - OK.\n");

  // Alternatively, you can set the access_token and the HTTP Client on the HttpServiceClientConfig
  Api::init(null, null, null, false);
  HttpServiceClientConfig::getInstance()->setClient(new TestHttpClient());
  HttpServiceClientConfig::getInstance()->setAccessToken($access_token);

  $request2 = getEventRequest($pixel_id, 2);

  $response2 = $request2->execute();

  print("Response: " . $response2->getBody() . "\n");
  print("Custom HTTP Service Request 2 - OK.\n");
}

function getEventRequest($pixel_id, $num) {
  $user_data = (new UserData())
    ->setEmail('joe' . $num . '@eg.com')
    ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
    ->setClientUserAgent($_SERVER['HTTP_USER_AGENT']);

  $custom_data = (new CustomData())
    ->setCurrency('usd')
    ->setValue(123.45);

  $event = (new Event())
    ->setEventName('Purchase')
    ->setEventTime(time())
    ->setEventSourceUrl('http://jaspers-market.com/product/123')
    ->setUserData($user_data)
    ->setCustomData($custom_data)
    ->setActionSource(ActionSource::WEBSITE);

  return (new EventRequest($pixel_id))
    ->setEvents(array($event));
}

class TestHttpClient implements HttpServiceInterface {
  public function executeRequest($url, $method, array $curl_options, array $headers, array $params) {
    $multipart_contents = [];

    foreach ($params as $key => $value) {
      if ($key === 'data') {
        $multipart_contents[] = [
          'name' => $key,
          'contents' => \GuzzleHttp\json_encode($value),
          'headers' => array('Content-Type' => 'multipart/form-data'),
        ];
      } else {
        $multipart_contents[] = [
          'name' => $key,
          'contents' => $value,
          'headers' => array('Content-Type' => 'multipart/form-data'),
        ];
      }
    }

    $body = new MultipartStream($multipart_contents);
    $request = new Request($method, $url, $headers, $body);

    $handler_stack = HandlerStack::create(
      new CurlHandler(['options' => $curl_options])
    );

    $client = new Client(['handler' => $handler_stack]);
    return $client->send($request);
  }
}

run($access_token, $pixel_id);
import time
import os
import sys
repo_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
sys.path.insert(1, repo_dir)

from facebook_business.adobjects.serverside.custom_data import CustomData
from facebook_business.adobjects.serverside.event import Event
from facebook_business.adobjects.serverside.event_request import EventRequest
from facebook_business.adobjects.serverside.http_service_interface import HttpServiceInterface
from facebook_business.adobjects.serverside.user_data import UserData
from facebook_business.api import FacebookAdsApi


def run(pixel_id, access_token):
    user_data = UserData(
        email="joe@eg.com",
        client_ip_address=request.META.get('REMOTE_ADDR'),
        client_user_agent=request.headers['User-Agent']
    )
    custom_data = CustomData(currency="usd", value=123.45, item_number="itemnumber-123")
    event = Event(
        event_name="Purchase",
        event_time=int(time.time()),
        user_data=user_data,
        custom_data=custom_data,
        data_processing_options=[],
        event_source_url='http://jaspers-market.com/product/123',
        action_source=ActionSource.WEBSITE
    )
    custom_http_client = CustomHttpClient()
    event_request = EventRequest(
        events=[event],
        pixel_id=pixel_id,
        http_client=custom_http_client,
        access_token=access_token
    )

    event_response = event_request.execute()
    print(event_response)
    print("Custom HTTP Service Request - OK.")

class CustomHttpClient(HttpServiceInterface):
    def execute(self, url, method, request_options, headers, params):
        import requests
        from facebook_business.adobjects.serverside.event_response import EventResponse

        response = requests.request(method, url, json=params, headers=headers).json()
        return EventResponse(
            events_received=response['events_received'],
            fbtrace_id=response['fbtrace_id'],
            messages=response['messages']
        )

if __name__ == '__main__':
    pixel_id = os.getenv("PIXEL_ID")
    access_token = os.getenv("ACCESS_TOKEN")
    if not (pixel_id and access_token):
        raise Exception("Missing required test config. Got pixel_id: '{pixel_id}', access_token: '{access_token}'".format(
            pixel_id=pixel_id,
            access_token=access_token
        ))

    run(pixel_id, access_token)
const bizSdk = require('facebook-nodejs-business-sdk');
const https = require('https');
const process = require('process');
const ServerEvent = bizSdk.ServerEvent;
const EventRequest = bizSdk.EventRequest;
const EventResponse = bizSdk.EventResponse;
const UserData = bizSdk.UserData;
const CustomData = bizSdk.CustomData;
const Content = bizSdk.Content;

const access_token = process.env.ACCESS_TOKEN;
const pixel_id = process.env.PIXEL_ID;

// Implements the HttpServiceInterface
class E2EHttpService {
  executeRequest(url, method, headers, params) {
    return new Promise((resolve, reject) => {
      const options = {
        port: 443,
        method,
        headers,
      }
      let body = '';
      const request = https.request(url, options, response => {
        response.on('data', chunk => {
          body += chunk.toString();
        });
        response.on('end', () => {
          return resolve(body);
        });
      }).on('error', reject);

      request.write(JSON.stringify(params));
      request.end();
    });
  }
}

void async function() {
  try {
    if (access_token === undefined || pixel_id === undefined) {
      throw new Error(`"Missing required test config. Got pixel_id: '${pixel_id}', access_token: '${access_token}'"`)
    }
    const userData = (new UserData())
      .setEmail('joe@eg.com')
      .setClientIpAddress(request.connection.remoteAddress)
      .setClientUserAgent(request.headers['user-agent']);

    const customData = (new CustomData())
      .setCurrency('usd')
      .setCustomProperties({custom1: 'value2'})
      .setValue(123.45);

    const serverEvent = (new ServerEvent())
      .setEventName('Purchase')
      .setEventTime(Math.floor(new Date() / 1000))
      .setUserData(userData)
      .setCustomData(customData)
      .setEventSourceUrl('http://jaspers-market.com/product/123')
      .setActionSource('website');

    const eventsData = [serverEvent];
    const eventRequest = (new EventRequest(access_token, pixel_id))
      .setHttpService(new E2EHttpService())
      .setEvents(eventsData);

    eventRequest.execute().then(response => {
      console.log('Custom HTTP Service Request OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
  } catch(error) {
    console.log(error);
    process.exit(1);
  }
}();
import com.facebook.ads.sdk.APIContext;
import com.facebook.ads.sdk.serverside.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class CONVERSIONS_API_EVENT_CREATE_CUSTOM_HTTP_SERVICE {
  public static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");
  public static final String PIXEL_ID = System.getenv("PIXEL_ID");

  public static void run() throws Exception {
    if (ACCESS_TOKEN == null || PIXEL_ID == null) {
      throw new Exception(String.format("Missing required test config. Got pixel_id: '%s', access_token: '%s'", PIXEL_ID, ACCESS_TOKEN));
    }

    APIContext context = new APIContext(ACCESS_TOKEN).enableDebug(true);
    context.setLogger(System.out);

    UserData userData = new UserData()
        .email("joe@eg.com")
        .clientIpAddress(clientIpAddress)
        .clientUserAgent(clientUserAgent);

    HashMap<String, String> customProperties = new HashMap<>();
    customProperties.put("item_number", "456");

    CustomData customData = new CustomData()
        .currency("usd")
        .customProperties(customProperties)
        .value(123.45F);

    Event pageViewEvent = new Event();
    pageViewEvent.eventName("Purchase")
        .eventTime(System.currentTimeMillis() / 1000L)
        .userData(userData)
        .customData(customData)
        .eventSourceUrl("http://jaspers-market.com/product/123")
        .actionSource(ActionSource.website);

    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(pageViewEvent);

    // Set the Custom HTTP Service Client
    HttpServiceInterface httpServiceClient = new E2EHttpServiceClient();
    eventRequest.setHttpServiceClient(httpServiceClient);

    EventResponse eventResponse = eventRequest.execute();
    System.out.println("Request was successful:");
    System.out.println(eventResponse);
  }

  public static void main(String[] args) {
    try {
      run();
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println(e.toString());
      System.exit(1);
    }
    System.exit(0);
  }

  private static class E2EHttpServiceClient implements HttpServiceInterface {
    @Override
    public EventResponse executeRequest(String url, HttpMethodEnum httpMethod, Map<String, String> headers, HttpServiceParams params) {
      EventResponse eventResponse = null;
      try {
        Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .create();
        URL requestUrl = new URL(url);

        HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
        connection.setRequestMethod(httpMethod.toString());
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/json");

        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.writeBytes(gson.toJson(params));
        out.flush();
        out.close();

        BufferedReader in = new BufferedReader(
            new InputStreamReader(connection.getInputStream())
        );
        String responseLine = in.readLine();
        StringBuffer response = new StringBuffer();
        while (responseLine != null) {
          response.append(responseLine);
          responseLine = in.readLine();
        }
        in.close();
        String responseString = response.toString();

        eventResponse = gson.fromJson(responseString, EventResponse.class);
      } catch (Exception e) {
        e.printStackTrace();
        System.exit(1);
      }
      return eventResponse;
    }
  }
}
require 'facebook_ads'

class CustomHttpClient < FacebookAds::ServerSide::HttpServiceInterface
    def execute(url, request_method, headers, params)
        require 'faraday'
        require 'json'

        raise Exception.new("Incorrect HTTP method: #{request_method}") if request_method != FacebookAds::ServerSide::HttpMethod::POST

        response = Faraday.post(url) do |request|
            headers.each do |key, value|
                request[key] = value
            end
            request.headers['Content-Type'] = 'application/json'
            request.body = params.to_json
        end

        parsed_response = JSON.load(response.body)

        return FacebookAds::ServerSide::EventResponse.new(
            events_received: parsed_response['events_received'],
            messages: parsed_response['messages'],
            fbtrace_id: parsed_response['fbtrace_id']
        )
    end
end

def main
    access_token = ENV['ACCESS_TOKEN']
    pixel_id = ENV['PIXEL_ID']
    unless access_token && pixel_id
        raise Exception.new("Missing required test config. Got pixel_id: '#{pixel_id}', access_token: '#{access_token}'")
    end

    FacebookAds.configure do |config|
        config.access_token = access_token
    end

    user_data = FacebookAds::ServerSide::UserData.new(
        email: 'joe@eg.com',
        client_ip_address: request.remote_ip,
        client_user_agent: request.user_agent
    )

    custom_data = FacebookAds::ServerSide::CustomData.new(
        currency: 'usd',
        value: 123.45
    )

    event = FacebookAds::ServerSide::Event.new(
        event_name: 'Purchase',
        event_time: Time.now.to_i,
        user_data: user_data,
        custom_data: custom_data,
        event_source_url: 'http://jaspers-market.com/product/123',
        action_source: 'website'
    )

    request = FacebookAds::ServerSide::EventRequest.new(
        pixel_id: pixel_id,
        events: [event],
        http_service_client: CustomHttpClient.new
    )

    response = request.execute
    print "Response: #{response}\n"
    print "Custom HTTP Service Request - OK."
end

main

測試您的事件要求

您可以使用 test_event_code 參數來測試您的事件要求。在事件管理工具中,前往資料來源 > 您的像素 > 測試事件頁籤下的「測試事件」工具,找到該測試程式碼。

注意:您必須將下面程式碼中的範例值(即 TEST12345)替換為您從測試事件頁籤中取得的測試程式碼。

...
$request = (new EventRequest($pixel_id))
    ->setTestEventCode('TEST12345')
    ->setEvents($events);

$response = $request->execute();
...
event_request = EventRequest(
    events=[event],
    test_event_code='TEST12345',
    pixel_id=pixel_id
)

result = event_request.execute()
...
    const eventRequest = (new EventRequest(access_token, pixel_id))
      .setTestEventCode('TEST12345')
      .setEvents(eventsData);

    eventRequest.execute().then(response => {
      console.log('Execute Request OK. Response: ', response);
    }, err => {
      console.log('Error: ', err);
    });
...
    EventRequest eventRequest = new EventRequest(PIXEL_ID, context);
    eventRequest.addDataItem(purchaseEvent);
    eventRequest.setTestEventCode("TEST12345");

    EventResponse response = eventRequest.execute();
...
request = FacebookAds::ServerSide::EventRequest.new(
    pixel_id: PIXEL_ID,
    test_event_code: 'TEST12345',
    events: [event]
)

response = request.execute

限制

我們目前不支援在發出並行批次要求或非同步要求時設定自訂 HTTP 服務介面。