本指南将详细说明如何使用 Campaign Manager 360 API Conversions
服务上传线下转化数据。在继续学习之前,建议您查看概览,简要了解线下转化情况并熟悉本指南中讨论的概念。
配置转化资源
转化数据上传流程的第一步是创建一个或多个 Conversion
资源对象。每个对象代表一个转化事件,并包含几个必填字段:
字段 | 说明 |
---|---|
floodlightActivityId |
与此转化相关联的 Floodlight 活动。 |
floodlightConfigurationId |
指定活动使用的 Floodlight 配置。 |
ordinal |
一个值,用于控制如何对来自同一设备或用户的同一天的转化进行去重。有关详情,请参阅常见问题解答。 |
timestampMicros |
转化的时间戳(以与 Unix 计时原点之间相隔的微秒数表示)。 |
此外,每个对象都必须包含以下字段之一:
字段 | 说明 |
---|---|
encryptedUserId |
从 %m 匹配宏或数据传输中获取的单个加密的用户 ID。 |
encryptedUserIdCandidates[] |
通过 %m 匹配宏或数据传输获取的经过加密的用户 ID 列表。系统会使用这些 ID 中第一个在 timestampMicros 之前记录的 Floodlight 曝光的 ID。如果没有任何 ID 与现有曝光匹配,系统会抛出错误。 |
dclid |
由 Campaign Manager 360 或 Display & Video 360 生成的展示广告点击标识符。 |
gclid |
由 Google Ads 或 Search Ads 360 生成的 Google 点击标识符。 |
matchId |
通过 Floodlight 代码传递到 Campaign Manager 360 的由广告客户创建的唯一标识符。 |
mobileDeviceId |
IDFA 或 AdID 格式的未加密移动设备 ID,或支持的 CTV 设备平台(Roku、Fire TV、Android TV、Apple TV、Xbox、三星、Vizio)所用的联网电视 IFA(广告标识符)。请注意,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(如上例所示),则需要在插入请求中提供一些加密方式的详细信息。具体而言,您需要知道:
加密来源,用于说明一批加密 ID 的来源。可接受的值为:
AD_SERVING
(对于源自 %m 匹配宏的 ID),或DATA_TRANSFER
(对于源自数据传输文件的 ID)。加密实体:用于加密用户 ID 的一组唯一值。如果来源是数据传输,则这些值通常与 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。