上傳轉換資料

本指南提供使用 Campaign Manager 360 API Conversions 服務上傳離線轉換的詳細操作說明。建議您先閱讀總覽,瞭解離線轉換簡介,並熟悉本指南所述的概念,然後再繼續。

設定轉換資源

轉換上傳程序的第一個步驟是建立一或多個 Conversion 資源物件。每個物件都代表單一轉換事件,並包含下列幾個必填欄位:

欄位 說明
floodlightActivityId 與此轉換相關聯的 Floodlight 活動。
floodlightConfigurationId 指定活動使用的 Floodlight 設定。
ordinal 同一天內,用於控制同一部裝置或使用者轉換次數的不重複值會刪除。詳情請參閱常見問題
timestampMicros 轉換時間戳記,以自 Unix Epoch 紀元時間起算的毫秒為單位。

此外,每個物件都必須包含下列任一欄位:

欄位 說明
encryptedUserId %m 比對巨集資料移轉取得的單一加密使用者 ID。
encryptedUserIdCandidates[] %m 比對巨集資料移轉取得的加密使用者 ID 清單。系統將使用第一個在指定 timestampMicros 之前記錄到 Floodlight 曝光的 ID。如果沒有任何 ID 與現有的曝光相符,就會擲回錯誤。
dclid Campaign Manager 360 或 Display & Video 360 產生的多媒體廣告點擊 ID
gclid Google Ads 或 Search Ads 360 產生的 Google 點擊 ID
matchId 透過 Floodlight 代碼傳送至 Campaign Manager 360 的專屬廣告客戶 ID。
mobileDeviceId IDFA 或 AdID 格式中的未加密行動 ID 或連網電視廣告 ID (IFA) 進行加密。您可以使用支援的連網電視裝置平台 (Roku、Fire TV、Android TV、Apple TV、Xbox、Samsung、Vizio)請注意,Google 不支援 YouTube 連網電視 IFA。

如需選填欄位,請參閱參考說明文件。請注意,數量 (選填) 必須至少是 1,讓報表在執行時計入特定指標 (例如轉換總數)。

以下範例說明如何建立簡單的轉換資源物件:

C#

// Generate a timestamp in milliseconds since Unix epoch.
TimeSpan timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1);
long currentTimeInMilliseconds = (long) timeSpan.TotalMilliseconds;

// Find the Floodlight configuration ID based on the provided activity ID.
FloodlightActivity floodlightActivity =
    service.FloodlightActivities.Get(profileId, floodlightActivityId).Execute();
long floodlightConfigurationId = (long) floodlightActivity.FloodlightConfigurationId;

// Create the conversion.
Conversion conversion = new Conversion();
conversion.EncryptedUserId = conversionUserId;
conversion.FloodlightActivityId = floodlightActivityId;
conversion.FloodlightConfigurationId = floodlightConfigurationId;
conversion.Ordinal = currentTimeInMilliseconds.ToString();
conversion.TimestampMicros = currentTimeInMilliseconds * 1000;

Java

long currentTimeInMilliseconds = System.currentTimeMillis();

// Find Floodlight configuration ID based on the provided activity ID.
FloodlightActivity floodlightActivity = reporting.floodlightActivities()
    .get(profileId, floodlightActivityId).execute();
long floodlightConfigurationId = floodlightActivity.getFloodlightConfigurationId();

Conversion conversion = new Conversion();
conversion.setEncryptedUserId(encryptedUserId);
conversion.setFloodlightActivityId(floodlightActivityId);
conversion.setFloodlightConfigurationId(floodlightConfigurationId);
conversion.setOrdinal(String.valueOf(currentTimeInMilliseconds));
conversion.setTimestampMicros(currentTimeInMilliseconds * 1000);

PHP

$currentTimeInMicros = time() * 1000 * 1000;

// Find Floodlight configuration ID based on provided activity ID.
$activity = $this->service->floodlightActivities->get(
    $values['user_profile_id'],
    $values['floodlight_activity_id']
);
$floodlightConfigId = $activity->getFloodlightConfigurationId();

$conversion = new Google_Service_Dfareporting_Conversion();
$conversion->setEncryptedUserId($values['encrypted_user_id']);
$conversion->setFloodlightActivityId($values['floodlight_activity_id']);
$conversion->setFloodlightConfigurationId($floodlightConfigId);
$conversion->setOrdinal($currentTimeInMicros);
$conversion->setTimestampMicros($currentTimeInMicros);

Python

# Look up the Floodlight configuration ID based on activity ID.
floodlight_activity = service.floodlightActivities().get(
    profileId=profile_id, id=floodlight_activity_id).execute()
floodlight_config_id = floodlight_activity['floodlightConfigurationId']

current_time_in_micros = int(time.time() * 1000000)

# Construct the conversion.
conversion = {
    'encryptedUserId': encrypted_user_id,
    'floodlightActivityId': floodlight_activity_id,
    'floodlightConfigurationId': floodlight_config_id,
    'ordinal': current_time_in_micros,
    'timestampMicros': current_time_in_micros
}

Ruby

# Look up the Floodlight configuration ID based on activity ID.
floodlight_activity = service.get_floodlight_activity(profile_id,
  floodlight_activity_id)
floodlight_config_id = floodlight_activity.floodlight_configuration_id

current_time_in_micros = DateTime.now.strftime('%Q').to_i * 1000

# Construct the conversion.
conversion = DfareportingUtils::API_NAMESPACE::Conversion.new(
  encrypted_user_id: encrypted_user_id,
  floodlight_activity_id: floodlight_activity_id,
  floodlight_configuration_id: floodlight_config_id,
  ordinal: current_time_in_micros,
  timestamp_micros: current_time_in_micros
)

指定加密資訊

如前例所示,如果您打算將離線轉換歸因給加密的使用者 ID,則必須提供一些詳細資料,說明系統如何在插入要求中加密這些機制。請特別注意以下事項:

  1. 加密來源,其說明批次加密 ID 的傳輸來源。可接受的值包括 AD_SERVING (來自 %m 比對巨集的 ID),如果是從資料移轉檔案取得的 ID,則為 DATA_TRANSFER

  2. 加密實體是一組不重複的值,用來加密使用者 ID。當來源是 %m 巨集時,這些值通常會與 Campaign Manager 360 帳戶相關;如果來源為 %m 巨集,則這些值與 Campaign Manager 360 廣告客戶有關,但並非一律如此。如果您不確定,詳情請洽詢 Campaign Manager 360 帳戶代表或 Campaign Manager 360 支援團隊

如有需要,請建立 EncryptionInfo 物件,並指定這些值,這是轉換上傳程序的第二個步驟:

C#

// Create the encryption info.
EncryptionInfo encryptionInfo = new EncryptionInfo();
encryptionInfo.EncryptionEntityId = encryptionEntityId;
encryptionInfo.EncryptionEntityType = encryptionEntityType;
encryptionInfo.EncryptionSource = encryptionSource;

Java

// Create the encryption info.
EncryptionInfo encryptionInfo = new EncryptionInfo();
encryptionInfo.setEncryptionEntityId(encryptionEntityId);
encryptionInfo.setEncryptionEntityType(encryptionEntityType);
encryptionInfo.setEncryptionSource(encryptionSource);

PHP

$encryptionInfo = new Google_Service_Dfareporting_EncryptionInfo();
$encryptionInfo->setEncryptionEntityId($values['encryption_entity_id']);
$encryptionInfo->setEncryptionEntityType($values['encryption_entity_type']);
$encryptionInfo->setEncryptionSource($values['encryption_source']);

Python

# Construct the encryption info.
encryption_info = {
    'encryptionEntityId': encryption_entity_id,
    'encryptionEntityType': encryption_entity_type,
    'encryptionSource': encryption_source
}

Ruby

# Construct the encryption info.
encryption_info = DfareportingUtils::API_NAMESPACE::EncryptionInfo.new(
  encryption_entity_id: encryption[:entity_id],
  encryption_entity_type: encryption[:entity_type],
  encryption_source: encryption[:source]
)

請注意,每個插入要求都只能包含一個 EncryptionInfo 物件。這表示指定請求中的所有轉換都必須來自相同的來源,且使用相同的加密實體。

產生插入要求

此程序的最後一個步驟,是透過呼叫 batchinsert 來上傳轉換資料。這個方法會接受 ConversionsBatchInsertRequest 物件,該物件會組合要上傳的轉換資料組合與相關的加密資訊 (如有必要):

C#

// Insert the conversion.
ConversionsBatchInsertRequest request = new ConversionsBatchInsertRequest();
request.Conversions = new List<Conversion>() { conversion };
request.EncryptionInfo = encryptionInfo;

ConversionsBatchInsertResponse response =
    service.Conversions.Batchinsert(request, profileId).Execute();

Java

ConversionsBatchInsertRequest request = new ConversionsBatchInsertRequest();
request.setConversions(ImmutableList.of(conversion));
request.setEncryptionInfo(encryptionInfo);

ConversionsBatchInsertResponse response = reporting.conversions()
    .batchinsert(profileId, request).execute();

PHP

$batch = new Google_Service_Dfareporting_ConversionsBatchInsertRequest();
$batch->setConversions([$conversion]);
$batch->setEncryptionInfo($encryptionInfo);

$result = $this->service->conversions->batchinsert(
    $values['user_profile_id'],
    $batch
);

Python

# Insert the conversion.
request_body = {
    'conversions': [conversion],
    'encryptionInfo': encryption_info
}
request = service.conversions().batchinsert(profileId=profile_id,
                                            body=request_body)
response = request.execute()

Ruby

# Construct the batch insert request.
batch_insert_request =
  DfareportingUtils::API_NAMESPACE::ConversionsBatchInsertRequest.new(
    conversions: [conversion],
    encryption_info: encryption_info
  )

# Insert the conversion.
result = service.batchinsert_conversion(profile_id, batch_insert_request)

請注意,Campaign Manager 360 會盡可能嘗試在要求中插入每次轉換,而不是將整個批次插入做為非全部或多筆交易。如果批次無法插入部分轉換,其他轉換可能仍可成功插入。因此,建議您檢查傳回的 ConversionsBatchInsertResponse,判斷每筆轉換的狀態:

C#

// Handle the batchinsert response.
if (!response.HasFailures.Value) {
  Console.WriteLine("Successfully inserted conversion for encrypted user ID {0}.",
      conversionUserId);
} else {
  Console.WriteLine("Error(s) inserting conversion for encrypted user ID {0}:",
      conversionUserId);

  ConversionStatus status = response.Status[0];
  foreach(ConversionError error in status.Errors) {
    Console.WriteLine("\t[{0}]: {1}", error.Code, error.Message);
  }
}

Java

if (!response.getHasFailures()) {
  System.out.printf("Successfully inserted conversion for encrypted user ID %s.%n",
      encryptedUserId);
} else {
  System.out.printf("Error(s) inserting conversion for encrypted user ID %s:%n",
      encryptedUserId);

  // Retrieve the conversion status and report any errors found. If multiple conversions
  // were included in the original request, the response would contain a status for each.
  ConversionStatus status = response.getStatus().get(0);
  for (ConversionError error : status.getErrors()) {
    System.out.printf("\t[%s]: %s.%n", error.getCode(), error.getMessage());
  }
}

PHP

if (!$result->getHasFailures()) {
    printf(
        'Successfully inserted conversion for encrypted user ID %s.',
        $values['encrypted_user_id']
    );
} else {
    printf(
        'Error(s) inserting conversion for encrypted user ID %s:<br><br>',
        $values['encrypted_user_id']
    );

    $status = $result->getStatus()[0];
    foreach ($status->getErrors() as $error) {
        printf('[%s] %s<br>', $error->getCode(), $error->getMessage());
    }
}

Python

if not response['hasFailures']:
  print ('Successfully inserted conversion for encrypted user ID %s.'
         % encrypted_user_id)
else:
  print ('Error(s) inserting conversion for encrypted user ID %s.'
         % encrypted_user_id)

  status = response['status'][0]
  for error in status['errors']:
    print '\t[%s]: %s' % (error['code'], error['message'])

Ruby

if result.has_failures
  puts format('Error(s) inserting conversion for encrypted user ID %s.',
    encrypted_user_id)

  status = result.status[0]
  status.errors.each do |error|
    puts format("\t[%s]: %s", error.code, error.message)
  end
else
  puts format('Successfully inserted conversion for encrypted user ID %s.',
    encrypted_user_id)
end

如上所示,回應的 status 欄位會包含原始要求中所含的每個轉換的 ConversionStatus 物件。如果只想查看轉換無法插入的轉換,可以使用 hasFailures 欄位快速判斷指定批次中的「任何」轉換是否失敗。

確認轉換已處理完畢

上傳的轉換通常會經過處理,並可在 24 小時內納入報表。如要確認您上傳的轉換是否處理完畢,建議您執行 Floodlight 曝光報表。和其他歸因報表不同的是,這類報表預設會傳回歸因資料 (與廣告建立關聯) 和未歸因的轉換。如此一來,即可迅速確認相關轉換是否已傳送至 Campaign Manager 360。