راهنمای توسعه‌دهنده API Reporting Attribution، راهنمای توسعه‌دهنده API گزارش Attribution، راهنمای توسعه‌دهنده API گزارش Attribution

همانطور که در اسناد Android Sandbox Privacy می خوانید، از دکمه Developer Preview یا Beta برای انتخاب نسخه برنامه ای که با آن کار می کنید استفاده کنید، زیرا ممکن است دستورالعمل ها متفاوت باشد.


ارائه بازخورد

Attribution Reporting API برای ارائه بهبود حریم خصوصی کاربر با حذف اتکا به شناسه‌های کاربر بین حزبی و پشتیبانی از موارد استفاده کلیدی برای اندازه‌گیری اسناد و تبدیل در بین برنامه‌ها طراحی شده است. این راهنمای توسعه‌دهنده نحوه پیکربندی و آزمایش APIهای گزارش Attribution را برای ثبت کلیک‌ها، بازدیدها و تبدیل‌های تبلیغاتی با فراخوانی روش‌هایی که محرک‌ها و منابع مربوطه را برای چنین رویدادهایی ثبت می‌کنند، شرح می‌دهد.

این راهنما به شما می آموزد که چگونه نقاط پایانی سرور را تنظیم کنید و یک برنامه مشتری بسازید که این خدمات را فراخوانی کند. درباره طراحی کلی Attribution Reporting API در طرح پیشنهادی بیشتر بیاموزید.

شرایط کلیدی

  • منابع انتساب به کلیک ها یا بازدیدها اشاره دارد.
  • محرک ها رویدادهایی هستند که می توانند به تبدیل ها نسبت داده شوند.
  • گزارش‌ها حاوی داده‌هایی درباره یک ماشه و منبع انتساب مربوطه هستند. این گزارش ها در پاسخ به رویدادهای محرک ارسال می شوند. Attribution Reporting API از گزارش‌های سطح رویداد و گزارش‌های جمع‌آوری‌شده پشتیبانی می‌کند.

قبل از اینکه شروع کنی

برای استفاده از Attribution Reporting API، وظایف سمت سرور و سمت سرویس گیرنده فهرست شده در بخش‌های زیر را تکمیل کنید.

نقاط پایانی API Reporting Attribution را تنظیم کنید

Attribution Reporting API به مجموعه‌ای از نقاط پایانی نیاز دارد که می‌توانید از دستگاه آزمایشی یا شبیه‌ساز به آنها دسترسی داشته باشید. برای هر یک از وظایف سمت سرور زیر یک نقطه پایانی ایجاد کنید:

چندین روش برای تنظیم نقاط پایانی مورد نیاز وجود دارد:

  • سریع ترین راه برای راه اندازی و اجرا، استقرار تعاریف سرویس OpenAPI v3 از مخزن کد نمونه ما در یک پلت فرم ساختگی یا میکروسرویس است. می توانید از Postman ، Prism یا هر پلتفرم سرور ساختگی دیگری که این قالب را می پذیرد استفاده کنید. هر نقطه پایانی را مستقر کنید و URI ها را برای استفاده در برنامه خود پیگیری کنید. برای تأیید تحویل گزارش، به تماس‌هایی که قبلاً با پلتفرم ساختگی یا بدون سرور برقرار شده است مراجعه کنید.
  • سرور مستقل خود را با استفاده از نمونه Kotlin مبتنی بر Spring Boot اجرا کنید. این سرور را در ارائه دهنده ابر یا زیرساخت داخلی خود مستقر کنید.
  • از تعاریف سرویس به عنوان مثال برای ادغام نقاط پایانی در سیستم موجود خود استفاده کنید.

پذیرش ثبت منبع

این نقطه پایانی باید از یک URI مشابه زیر قابل آدرس دهی باشد:

https://adtech.example/attribution_source

هنگامی که یک برنامه مشتری یک منبع انتساب را ثبت می کند ، URI را برای این نقطه پایانی سرور ارائه می دهد. سپس Attribution Reporting API درخواستی می دهد و یکی از سرصفحه های زیر را شامل می شود:

  • برای رویدادهای کلیک کنید:

    Attribution-Reporting-Source-Info: navigation
    
  • برای مشاهده رویدادها:

    Attribution-Reporting-Source-Info: event
    

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهد:

// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  // Attribution source metadata specifying histogram contributions in aggregate
  // report.
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  },

    "debug_key": "[64-bit unsigned integer]",
    "debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا یک مثال با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Source: {
  "destination": "android-app://com.example.advertiser",
  "source_event_id": "234",
  "expiry": "259200",
  "event_report_window": "172800",
  "aggregatable_report_window": "172800",
  "priority": "5",
  "filter_data": {
    "product_id": ["1234"]
  },
  "aggregation_keys": {
  // Generates a "0x159" key piece named (low order bits of the key) for the key
  // named "campaignCounts".
  // User saw an ad from campaign 345 (out of 511).
    "campaignCounts": "0x159",

  // Generates a "0x5" key piece (low order bits of the key) for the key named
  // "geoValue".
  // Source-side geo region = 5 (US), out of a possible ~100 regions.
    "geoValue": "0x5",
  },
  // Opts in to receiving verbose debug reports
  "debug_reporting": true
}

Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890

اگر Attribution-Reporting-Redirects شامل URI شرکای فناوری تبلیغات باشد، API گزارش Attribution درخواست مشابهی را برای هر URI ارسال می کند. هر شریک فناوری تبلیغاتی باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  }
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

ثبت نام ماشه تبدیل را بپذیرید

این نقطه پایانی باید از یک URI مشابه زیر قابل آدرس دهی باشد:

https://adtech.example/attribution_trigger

هنگامی که یک برنامه مشتری یک رویداد ماشه را ثبت می کند ، URI را برای این نقطه پایانی سرور ارائه می دهد. سپس Attribution Reporting API درخواستی می دهد و یکی از سرصفحه های زیر را شامل می شود:

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data returned" in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // "filter" and "not_filters" are optional fields which allow configuring
    // event trigger data based on source's filter_data. They consist of a
    // filter set, which is a list of filter maps. An event_trigger_data object
    // is ignored if none of the filter maps in the set match the source's
    // filter data.
    // Note: "source_type" can be used as a key in a filter map to filter based
    // on the source's "navigation" or "event" type. The first
    // Event-Trigger that matches (based on the filters/not_filters) will be
    // used for report generation. If none of the event-triggers match, no
    // event report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it won't be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it won't
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  // Specify a list of dictionaries that generates aggregation keys.
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]]
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16]
  // to contribute to each key that is attached to aggregation keys in the
  // order they are generated.
  "aggregatable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the
     // aggregate histogram.
    {
     "[key_name]": [value]
    },
    ..
  ],
  aggregatable_deduplication_keys: [{
  deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_H]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
  },
  ...
  {
  "deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_D]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
    }
  ]

  "debug_key": "[64-bit unsigned integer]",
  "debug_reporting": [boolean]

}
// Specify additional ad tech URLs to register this trigger with.
// Repeated Header field "Attribution-Reporting-Redirect"
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا یک مثال با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    "trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["event"]
    }]
  },
  {
    "trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["navigation"]
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary independently adds pieces to multiple source keys.
    {
      // Conversion type purchase = 2 at a 9-bit offset, i.e. 2 << 9.
      // A 9-bit offset is needed because there are 511 possible campaigns,
      // which takes up 9 bits in the resulting key.
      "key_piece": "0x400",// Conversion type purchase = 2
      // Apply this key piece to:
      "source_keys": ["campaignCounts"]
       // Filter strings can not exceed 25 characters
    },
    {
      // Purchase category shirts = 21 at a 7-bit offset, i.e. 21 << 7.
      // A 7-bit offset is needed because there are ~100 regions for the geo
      // key, which takes up 7 bits of space in the resulting key.
      "key_piece": "0xA80",
      // Apply this key piece to:
      "source_keys": ["geoValue", "nonMatchingIdsAreIgnored"]
      // source_key values must not exceed the limit of 25 characters
    }
  ],
  "aggregatable_values":
    {
      // Privacy budget for each key is L1 / 2 = 2^15 (32768).
      // Conversion count was 1.
      // Scale the count to use the full budget allocated: 1 * 32768 = 32768.
      "campaignCounts": 32768,

      // Purchase price was $52.
      // Purchase values for the app range from $1 to $1,024 (integers only).
      // Scaling factor applied is 32768 / 1024 = 32.
      // For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
      "geoValue": 1664
    }
  ,
  // aggregatable_deduplication_keys is an optional field. Up to 50 "keys"
  // can be included in the aggregatable_deduplication_keys list. Filters, not
  // filters, and deduplication_key are optional fields. If deduplication_key
  // is omitted, it will be treated as a null value. See
  // https://wicg.github.io/attribution-reporting-api/#triggering-aggregatable-attribution
  aggregatable_deduplication_keys:
  [
    {
    deduplication_key": 3,
        "filters": {
          "category": [A]
        }
    },
    {
    "deduplication_key": 4,
        "filters": {
          "category": [C, D]
        },
        "not_filters": {
          "category": [F]
        }
    }
  ]
  // Opts into receiving verbose debug reports
  "debug_reporting": true
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567

محدودیت 25 بایت برای هر شناسه کلید تجمعی و رشته فیلتر وجود دارد. این بدان معناست که شناسه‌های کلید تجمعی و رشته‌های فیلتر نباید از ۲۵ کاراکتر تجاوز کنند. در این مثال، campaignCounts 14 کاراکتر است، بنابراین یک شناسه کلید تجمعی معتبر است، و 1234 4 کاراکتر است، بنابراین یک رشته فیلتر معتبر است. اگر شناسه کلید تجمیع یا رشته فیلتر بیش از 25 کاراکتر باشد، ماشه نادیده گرفته می شود.

اگر Attribution-Reporting-Redirect شامل URI شرکای فناوری تبلیغات باشد، API گزارش Attribution درخواست مشابهی را برای هر URI ارسال می کند. هر شریک فناوری تبلیغاتی باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data" returned in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // filter and not_filters are optional fields which allow configuring
    // different event trigger data based on source's filter_data. They
    // consist of a filter set, which is a list of filter maps. An
    // event_trigger_data object is ignored if none of the filter maps in the
    // set match the source's filter data. Note: "source_type" can be used as
    // a key in a filter map to filter based on the source's "navigation" or
    // "event" type. The first Event-Trigger that matches (based on the
    // filters/not_filters) will be used for report generation. If none of the
    // event-triggers match, no report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it will not be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it will not
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]],
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16] to
  // contribute to each key that is attached to aggregation keys in the order they
  // are generated.
  "aggregatable_values": [
    // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
    // histogram.
    {
     "[key_name]": [value]
    }
  ]
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

گزارش های سطح رویداد را بپذیرید

این نقطه پایانی باید از یک URI آدرس دهی شود. برای اطلاعات بیشتر در مورد ثبت نام URI، به ثبت نام برای یک حساب Sandbox حریم خصوصی مراجعه کنید. (URI از مبدأ سرورهای مورد استفاده برای پذیرش ثبت منبع و ثبت راه‌انداز استنباط می‌شود.) با استفاده از مثال URI برای نقاط پایانی که ثبت منبع را می‌پذیرند و ثبت ماشه را می‌پذیرند ، URI این نقطه پایانی به صورت زیر است:

https://adtech.example/.well-known/attribution-reporting/report-event-attribution

این سرور را برای پذیرش درخواست‌های JSON که از فرمت زیر استفاده می‌کنند پیکربندی کنید:

{
  "attribution_destination": "android-app://com.advertiser.example",
  "source_event_id": "12345678",
  "trigger_data": "2",
  "report_id": "12324323",
  "source_type": "navigation",
  "randomized_trigger_rate": "0.02"
   [Optional] "source_debug_key": "[64-bit unsigned integer]",
   [Optional] "trigger_debug_key": "[64-bit unsigned integer]",
}

کلیدهای اشکال زدایی به شما اجازه می دهد تا بینش بیشتری در مورد گزارش های اسناد شما داشته باشید. درباره پیکربندی آنها بیشتر بیاموزید .

گزارش های انبوه را بپذیرید

این نقطه پایانی باید از یک URI آدرس دهی شود. برای اطلاعات بیشتر در مورد ثبت نام URI، به ثبت نام برای یک حساب Sandbox حریم خصوصی مراجعه کنید. (URI از مبدأ سرورهای مورد استفاده برای پذیرش ثبت منبع و ثبت راه‌انداز استنباط می‌شود.) با استفاده از مثال URI برای نقاط پایانی که ثبت منبع را می‌پذیرند و ثبت ماشه را می‌پذیرند ، URI این نقطه پایانی به صورت زیر است:

https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution

هر دو فیلد رمزگذاری شده و رمزگذاری نشده برای گزارش های جمع آوری شده پر شده اند. گزارش‌های رمزگذاری شده شما را قادر می‌سازد تا آزمایش را با سرویس تجمیع آغاز کنید، در حالی که فیلد رمزگذاری نشده بینشی را در مورد نحوه ساختاربندی داده‌ها توسط جفت‌های کلید-مقدار تنظیم شده ارائه می‌دهد.

این سرور را برای پذیرش درخواست‌های JSON که از فرمت زیر استفاده می‌کنند پیکربندی کنید:

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform does not yet encrypt aggregate reports.
  // Currently, the "debug_cleartext_payload" field holds unencrypted reports.
  "aggregation_service_payloads": [
    {
      "payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
      "key_id": "[string identifying public key used to encrypt payload]",

      "debug_cleartext_payload": "[unencrypted payload]"
    },
  ],

  "source_debug_key": "[64 bit unsigned integer]",
  "trigger_debug_key": "[64 bit unsigned integer]"
}

کلیدهای اشکال زدایی به شما اجازه می دهد تا بینش بیشتری در مورد گزارش های اسناد شما داشته باشید. درباره پیکربندی آنها بیشتر بیاموزید .

سرویس گیرنده اندروید را تنظیم کنید

برنامه مشتری منابع و محرک‌های انتساب را ثبت می‌کند و تولید گزارش در سطح رویداد و قابل جمع‌آوری را فعال می‌کند. برای آماده کردن دستگاه یا شبیه‌ساز کلاینت Android برای استفاده از Attribution Reporting API، موارد زیر را انجام دهید:

  1. محیط توسعه خود را برای Privacy Sandbox در Android تنظیم کنید .
  2. یک تصویر سیستم را روی یک دستگاه پشتیبانی شده نصب کنید یا یک شبیه‌ساز راه‌اندازی کنید که شامل پشتیبانی از Privacy Sandbox در Android است.
  3. با اجرای دستور ADB زیر دسترسی به Attribution Reporting API را فعال کنید . (API به طور پیش فرض غیرفعال است.)

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
    
  4. اگر به صورت محلی API گزارش Attribution را آزمایش می کنید (مانند آزمایش روی دستگاهی که به صورت فیزیکی به آن دسترسی دارید)، این دستور را برای غیرفعال کردن ثبت نام اجرا کنید:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
    
  5. مجوز ACCESS_ADSERVICES_ATTRIBUTION را در فایل Manifest Android خود وارد کنید و یک پیکربندی خدمات تبلیغاتی برای برنامه خود ایجاد کنید تا از APIهای گزارش Attribution استفاده کند:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (اختیاری) اگر قصد دریافت گزارش های اشکال زدایی را دارید، مجوز ACCESS_ADSERVICES_AD_ID را در فایل Manifest Android خود قرار دهید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. به پیکربندی سرویس های تبلیغاتی در عنصر <application> مانیفست خود ارجاع دهید:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. منبع XML خدمات تبلیغاتی را که در مانیفست ارجاع داده شده است، مشخص کنید، مانند res/xml/ad_services_config.xml . درباره مجوزهای خدمات تبلیغات و کنترل دسترسی SDK بیشتر بیاموزید.

    <ad-services-config>
        <attribution allowAllToAccess="true" />
    </ad-services-config>
    

ثبت رویدادهای تبلیغاتی

برنامه شما باید منابع و تبدیل ها را در صورت وقوع ثبت کند تا اطمینان حاصل شود که به درستی گزارش شده اند. کلاس MeasurementManager دارای روش هایی است که به شما کمک می کند رویدادهای منبع اسناد و محرک های تبدیل را ثبت کنید.

یک رویداد منبع انتساب را ثبت کنید

هنگامی که یک تبلیغ مشاهده یا کلیک می شود، یک برنامه ناشر registerSource() برای ثبت منبع انتساب همانطور که در قطعه کد نشان داده شده است فرا می خواند.

Attribution Reporting API از انواع رویدادهای منبع انتساب زیر پشتیبانی می کند:

  • کلیک‌هایی که معمولاً در یک روش پاسخ به تماس مشابه onClick() ثبت می‌کنید. رویداد ماشه مربوطه معمولاً بلافاصله پس از رویداد کلیک رخ می دهد. این نوع رویداد اطلاعات بیشتری در مورد تعامل کاربر ارائه می دهد و بنابراین نوع خوبی از منبع انتساب برای اولویت بالا است.
  • نماهایی که معمولاً آنها را در یک روش بازگشت به تماس مشابه با onAdShown() ثبت می‌کنید. رویداد آغازگر مربوطه ممکن است ساعت ها یا روزها پس از رویداد مشاهده رخ دهد.

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
  Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
    exampleClickEvent = event
    true
}

// Register Click Event
measurementManager.registerSource(
        attributionSourceUri,
        exampleClickEvent,
        CALLBACK_EXECUTOR,
        future::complete)

// Register View Event
measurementManager.registerSource(
        attributionSourceUri,
        null,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
Uri attributionSourceUri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event)) -> {
    exampleClickEvent = event;
    return true;
}

// Register Click Event
measurementManager.registerSource(attributionSourceUri, exampleClickEvent,
        CALLBACK_EXECUTOR, future::complete);

// Register View Event
measurementManager.registerSource(attributionSourceUri, null,
        CALLBACK_EXECUTOR, future::complete);

پس از ثبت نام، API یک درخواست HTTP POST به نقطه پایانی سرویس در آدرس مشخص شده توسط attributionSourceUri ارسال می کند. پاسخ نقطه پایانی شامل مقادیر destination, source_event_id, expiry و source_priority است.

اگر فناوری تبلیغات مبدأ بخواهد ثبت‌های منبع را به اشتراک بگذارد، URI منبع انتساب اصلی می‌تواند شامل تغییر مسیرها به سایر نقاط پایانی فناوری تبلیغات باشد. محدودیت ها و قوانین قابل اعمال برای تغییر مسیرها در پیشنهاد فنی به تفصیل آمده است.

پشتیبانی برای تغییر مسیرهای زنجیره ای برای registerSource و registerTrigger اضافه شده است. علاوه بر هدر ثبت نام، مصرف کننده API اکنون می تواند یک تغییر مسیر HTTP را به عنوان پاسخ سرور ارائه دهد که شامل کد وضعیت 302 و هدر "مکان" به همراه URL بعدی برای بازدید برای ثبت نام اضافی است.

فقط از قسمت "مقصد" ارائه شده در اولین بازدید در سراسر زنجیره دیزی استفاده می شود. تعداد بازدیدها دارای محدودیتی مشابه سرصفحه های «Attribution-Reporting-Redirect» است. این پشتیبانی تغییر مسیر علاوه بر پشتیبانی موجود "Attribution-Reporting-Redirect" است و اگر هر دو وجود داشته باشند، "Attribution-Reporting-Redirect" اولویت دارد.

یک رویداد محرک تبدیل را ثبت کنید

برای ثبت یک رویداد تریگر تبدیل، با registerTrigger() در برنامه خود تماس بگیرید:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
    Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts trigger registration.
Uri attributionTriggerUri =
        Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

پس از ثبت نام، API یک درخواست HTTP POST به نقطه پایانی سرویس در آدرس مشخص شده توسط attributionTriggerUri ارسال می کند. پاسخ نقطه پایانی شامل مقادیری برای گزارش‌های رویداد و انبوه است.

اگر پلت فرم مبدأ فناوری تبلیغات اجازه اشتراک‌گذاری ثبت‌های راه‌انداز را بدهد، URI می‌تواند شامل تغییر مسیرها به URI‌هایی باشد که متعلق به سایر پلت‌فرم‌های فناوری تبلیغات هستند. محدودیت ها و قوانین قابل اعمال برای تغییر مسیرها در پیشنهاد فنی به تفصیل آمده است.

ثبت نام متقابل برنامه و اندازه گیری وب

در موردی که هر دو برنامه و مرورگر در سفر کاربر از منبع به راه‌انداز نقش دارند ، تفاوت‌های ظریفی در اجرای ثبت رویدادهای تبلیغاتی وجود دارد. اگر کاربر تبلیغی را در یک برنامه ببیند و برای تبدیل به یک مرورگر هدایت شود، منبع توسط برنامه و تبدیل توسط مرورگر وب ثبت می شود. به طور مشابه، اگر کاربر از یک مرورگر وب شروع به کار کند و برای تبدیل به برنامه ای هدایت شود، مرورگر منبع را ثبت می کند و برنامه تبدیل را ثبت می کند.

از آنجایی که تفاوت‌هایی در نحوه سازمان‌دهی فناوری‌های تبلیغاتی در وب و اندروید وجود دارد، ما API‌های جدیدی را برای ثبت منابع و محرک‌ها در مرورگرها اضافه کرده‌ایم. تفاوت اصلی بین این APIها و APIهای مبتنی بر برنامه مربوطه در این است که ما از مرورگر انتظار داریم ریدایرکت ها را دنبال کند، فیلترهای خاص مرورگر را اعمال کند و با فراخوانی registerWebSource() یا registerWebTrigger() ثبت نام های معتبر را به پلتفرم منتقل کند.

قطعه کد زیر نمونه‌ای از فراخوانی API را نشان می‌دهد که مرورگر قبل از هدایت کاربر به یک برنامه برای ثبت منبع انتساب انجام می‌دهد:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager =
        context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
val sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build()

val sourceParams = Arrays.asList(sourceParam1, sourceParam2, sourceParam3)
val publisherOrigin = Uri.parse("https://publisher.example")
val appDestination = Uri.parse("android-app://com.example.store")
val webDestination = Uri.parse("https://example.com")

val future = CompletableFuture<Void>()

adView.setOnTouchListener {_: View?, event: MotionEvent? ->
    exampleClickEvent = event
    true
}
val clickRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(event)
      .build()
val viewRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(null)
      .build()

// Register a web source for a click event.
measurementManager.registerWebSource(
        clickRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

// Register a web source for a view event.
measurementManager.registerWebSource(
        viewRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
WebSourceParams sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebSourceParams sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

WebSourceParams sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build();

List<WebSourceParams> sourceParams =
        Arrays.asList(sourceParam1, sourceParam2, sourceParam3);
Uri publisherOrigin = Uri.parse("https://publisher.example");
Uri appDestination = Uri.parse("android-app://com.example.store");
Uri webDestination = Uri.parse("https://example.com");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event) -> {
    exampleClickEvent = event;
    return true;
}

WebSourceRegistrationRequest clickRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(event)
    .build();
WebSourceRegistrationRequest viewRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(null)
    .build();

// Register a web source for a click event.
measurementManager.registerWebSource(clickRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

// Register a web source for a view event.
measurementManager.registerWebSource(viewRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

قطعه کد زیر نمونه ای از تماس API را نشان می دهد که مرورگر برای ثبت تبدیل پس از هدایت کاربر از برنامه انجام می دهد:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URIs of the server-side endpoints that accept trigger registration.
val triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val triggerParams = Arrays.asList(triggerParam1, triggerParam2)
val advertiserOrigin = Uri.parse("https://advertiser.example")

val future = CompletableFuture<Void>()

val triggerRegistrationRequest = WebTriggerRegistrationRequest.Builder(
        triggerParams,
        advertiserOrigin)
    .build()

// Register the web trigger (conversion).
measurementManager.registerWebTrigger(
    triggerRegistrationRequest,
    CALLBACK_EXECUTOR,
    future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept trigger registration.
WebTriggerParams triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebTriggerParams triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

List<WebTriggerParams> triggerParams =
        Arrays.asList(triggerParam1, triggerParam2);
Uri advertiserOrigin = Uri.parse("https://advertiser.example");

CompletableFuture<Void> future = new CompletableFuture<>();

WebTriggerRegistrationRequest triggerRegistrationRequest =
        new WebTriggerRegistrationRequest.Builder(
            triggerParams, advertiserOrigin)
    .build();

// Register the web trigger (conversion).
measurementManager.registerWebTrigger( triggerRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

اضافه کردن نویز برای حفظ حریم خصوصی

گزارش‌های سطح رویداد حاوی مقصد، شناسه منبع انتساب و داده‌های راه‌انداز است. آنها در قالب اصلی (غیر رمزگذاری نشده) به منبع گزارش ارسال می شوند. برای محافظت از حریم خصوصی کاربر، می توان نویز اضافه کرد تا شناسایی یک کاربر را دشوارتر کند. گزارش‌های نویز در سطح رویداد مطابق با چارچوب تفاوت حریم خصوصی تولید و ارسال می‌شوند. این مقادیر درصد نویز پیش فرض برای سناریوهای مختلف است:

نوع منبع

مقدار مقصد منبع

احتمال گزارش نویز در هر ثبت منبع

چشم انداز

یا برنامه یا وب

0.0000025

چشم انداز

اپلیکیشن و وب

0.0000042

کلیک

یا برنامه یا وب

0.0024263

کلیک

اپلیکیشن و وب

0.0170218

در اندازه‌گیری اسناد برنامه به وب، که در آن منابع می‌توانند تبدیل به مقصد برنامه و وب را ایجاد کنند، گزارش‌های سطح رویداد می‌توانند مشخص کنند که آغازگر در برنامه یا وب رخ داده است. برای جبران این جزئیات بیشتر، گزارش‌های نویز تولید شده تا 7 برابر برای کلیک و ~ 1.7 برابر برای بازدید هستند.

برخی از فناوری‌های تبلیغاتی برای مشخص کردن اینکه راه‌انداز در مقصد برنامه یا وب رخ داده است، به گزارش‌های سطح رویداد نیاز ندارند. فن‌آوران تبلیغات می‌توانند از قسمت coarse_event_report_destinations در زیر عنوان Attribution-Reporting-Register-Source برای کاهش نویز استفاده کنند. اگر منبعی با فیلد coarse_event_report_destinations مشخص شده برنده انتساب شود، گزارش حاصله شامل هر دو مقصد برنامه و وب بدون تمایز در مورد محل وقوع واقعی است.

در مثال‌های زیر، کاربر روی یک تبلیغ کلیک می‌کند و آن منبع در API ثبت می‌شود. سپس کاربر هم در برنامه تبلیغ کننده و هم در وب سایت تبلیغ کننده تبدیل می کند. هر دوی این تبدیل ها به عنوان محرک ثبت می شوند و به کلیک اولیه نسبت داده می شوند.

هدر HTTP ثبت منبع مبتنی بر کلیک:

Attribution-Reporting-Register-Source: {
    "destination": "android-app://com.advertiser.example",
    "web_destination": "https://advertiser.com",
    "source_event_id": "234",
    "expiry": "60000",
    "priority": "5",
    // Ad tech opts out of receiving app-web destination distinction
    // in event report, avoids additional noise
    "coarse_event_report_destinations": "true"
}

یک ماشه از برنامه با نام بسته com.advertiser.example ثبت شده است:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "1",
    "priority": "1"
    }],
}

یک ماشه از یک مرورگر از وب سایت با دامنه eTLD+1 https://advertiser.com ثبت می شود:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "2",
    "priority": "2"
    }],
}

گزارش‌های سطح رویداد حاصل تولید می‌شوند. با فرض اینکه هر دو محرک به منبع نسبت داده شوند، گزارش‌های سطح رویداد زیر تولید می‌شوند:

  {
    "attribution_destination": ["android-app://com.advertiser.example,https://advertiser.com"],
    "scheduled_report_time": "800176400",
    "source_event_id": "53234",
    "trigger_data": "1",
    // Can be "event" if source were registered by user viewing the ad
    "source_type": "navigation",
    // Would be 0.0170218 without coarse_event_report_destinations as true in the source
    "randomized_trigger_rate": 0.0024263
  }

تولید و ارائه گزارش

Attribution Reporting API گزارش‌هایی را به نقاط پایانی سرور شما ارسال می‌کند که گزارش‌های سطح رویداد و گزارش‌های جمع‌آوری‌شده را می‌پذیرند.

مشاغل گزارش دهی را مجبور به اجرا کنید

پس از ثبت یک رویداد منبع انتساب یا ثبت یک رویداد آغازگر، سیستم کار گزارش را برای اجرا برنامه ریزی می کند. به طور پیش فرض، این کار هر 4 ساعت یکبار اجرا می شود. برای اهداف آزمایشی، می‌توانید کارهای گزارش‌دهی را مجبور به اجرا کنید یا فواصل بین کارها را کوتاه کنید.

اجباری کردن کار انتساب برای اجرا:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 5

اجباری کردن کار گزارش‌دهی در سطح رویداد:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 3

کار گزارش انبوهی را مجبور به اجرا کنید:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 7

خروجی logcat را بررسی کنید تا ببینید کارها چه زمانی اجرا شده اند. باید چیزی شبیه به زیر باشد:

JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true

تحویل اجباری گزارش ها

حتی اگر کار گزارش‌دهی مجبور به اجرا شود، سیستم همچنان گزارش‌ها را طبق زمان‌های تحویل برنامه‌ریزی شده ارسال می‌کند که از چند ساعت تا چند روز متغیر است. برای اهداف آزمایشی، می‌توانید زمان سیستم دستگاه را پس از تأخیرهای برنامه‌ریزی‌شده برای شروع تحویل گزارش پیش ببرید.

گزارش ها را روی سرور خود تأیید کنید

پس از ارسال گزارش‌ها، با بررسی گزارش‌های دریافتی، گزارش‌های مربوط به سرور مانند تاریخچه سرور ساختگی یا سیستم سفارشی خود، تحویل را تأیید کنید.

گزارش انبوه خود را رمزگشایی کنید

هنگام دریافت گزارش انبوه، فیلد debug_cleartext_payload یک نسخه رمزگذاری نشده از گزارش انبوه شما را نگه می دارد. در حالی که این نسخه از گزارش شما رمزگذاری نشده است، هنوز باید رمزگشایی شود.

در زیر نمونه ای از رمزگشایی محتویات فیلد debug_cleartext_payload در دو مرحله آورده شده است: اولی با استفاده از رمزگشایی Base 64 و دومی با استفاده از رمزگشایی CBOR.

String base64DebugPayload  = "omRkYXRhgqJldmFsdWVEAAAGgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAKhaJldmFsdWVEAACAAGZidWNrZXRQAAAAAAAAAAAAAAAAAAAFWWlvcGVyYXRpb25paGlzdG9ncmFt";
byte[] cborEncoded = Base64.getDecoder().decode(base64DebugPayload);

// CbodDecoder comes from this library https://github.com/c-rack/cbor-java
final List<DataItem> dataItems = new CborDecoder(new ByteArrayInputStream(cborEncoded)).decode();

// In here you can see the contents, but the value will be something like:
// Data items: [{ data: [{ value: co.nstant.in.cbor.model.ByteString@a8b5c07a,
//   bucket: co.nstant.in.cbor.model.ByteString@f812097d },
//   { value: co.nstant.in.cbor.model.ByteString@a8b5dfc0,
//   bucket: co.nstant.in.cbor.model.ByteString@f8120934 }], operation: histogram }]
Log.d("Data items : " + dataItems);

// In order to see the value for bucket and value, you can traverse the data
// and get their values, something like this:
final Map payload = (Map) dataItems.get(0);
final Array payloadArray = (Array) payload.get(new UnicodeString("data"));

payloadArray.getDataItems().forEach(i -> {
    BigInteger value = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("value"))).getBytes());
    BigInteger bucket = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("bucket"))).getBytes());
    Log.d("value : " + value + " ;bucket : " + bucket);
});

آزمایش کردن

برای کمک به شما در شروع کار با Attribution Reporting API، می‌توانید از پروژه MeasurementSampleApp در GitHub استفاده کنید. این برنامه نمونه ثبت منبع منبع و ثبت راه‌انداز را نشان می‌دهد.

برای نقاط پایانی سرور، منابع مرجع زیر یا راه حل سفارشی خود را در نظر بگیرید:

  • MeasurementAdTechServerSpec شامل تعاریف سرویس OpenAPI است که می تواند در پلتفرم های ساختگی یا میکروسرویس پشتیبانی شده مستقر شود.
  • MeasurementAdTechServer شامل اجرای مرجع یک سرور ساختگی بر اساس برنامه Spring Boot برای Google App Engine است.

پیش نیازها

APIهای ساختگی را در نقاط پایانی راه دور قابل دسترسی از دستگاه آزمایشی یا شبیه ساز خود مستقر کنید. برای سهولت تست، به پروژه های نمونه MeasurementAdTechServerSpec و MeasurementAdTechServer مراجعه کنید.

عملکرد برای آزمایش

ویژگی های آینده

پیکربندی انعطاف پذیر در سطح رویداد

پیکربندی پیش‌فرض برای گزارش سطح رویداد برای شروع آزمایش ابزار توصیه می‌شود، اما ممکن است برای همه موارد استفاده ایده‌آل نباشد. Attribution Reporting API از پیکربندی‌های اختیاری و انعطاف‌پذیرتر پشتیبانی می‌کند تا فناوری‌های تبلیغاتی کنترل ساختار گزارش‌های سطح رویداد خود را افزایش دهند و بتوانند کاربرد داده‌ها را به حداکثر برسانند. این انعطاف‌پذیری اضافی در دو مرحله به API گزارش اسناد معرفی می‌شود:

  • فاز 1 : پیکربندی سطح رویداد انعطاف پذیر Lite. زیر مجموعه ای از فاز 2
  • فاز 2 : نسخه کامل پیکربندی سطح رویداد انعطاف پذیر.

مرحله 1: سطح رویداد انعطاف پذیر Lite

ما دو پارامتر اختیاری زیر را در Attribution-Reporting-Register-Source به JSON اضافه می کنیم:

  • max_event_level_reports
  • event_report_windows
{
  ...
  // Optional. This is a parameter that acts across all trigger types for the
  // lifetime of this source. It restricts the total number of event-level
  // reports that this source can generate. After this maximum is hit, the
  // source is no longer capable of producing any new data. The use of
  // priority in the trigger attribution algorithm in the case of multiple
  // attributable triggers remains unchanged. Defaults to 3 for navigation
  // sources and 1 for event sources
  "max_event_level_reports": <int>,

  // Optional. Represents a series of time windows, starting at 0. Reports
  // for this source will be delivered an hour after the end of each window.
  // Time is encoded as seconds after source registration. If
  // event_report_windows is omitted, will use the default windows. This
  // field is mutually exclusive with the existing `event_report_window` field.
  // // End time is exclusive.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

نمونه پیکربندی سفارشی

این پیکربندی نمونه از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد برای دریافت گزارش‌ها در پنجره‌های گزارش قبلی بهینه‌سازی کند.

{
  ...
  "max_event_level_reports": 2,
  "event_report_windows": {
    "end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
  }
}

فاز 2: سطح رویداد کاملا انعطاف پذیر

علاوه بر پارامترهایی که در فاز 1 اضافه شدند، یک پارامتر اختیاری trigger_specs به JSON در Attribution-Reporting-Register-Source اضافه می کنیم.

{
  // A trigger spec is a set of matching criteria, along with a scheme to
  // generate bucketized output based on accumulated values across multiple
  // triggers within the specified event_report_window. There will be a limit on
  // the number of specs possible to define for a source.
  "trigger_specs": [{
    // This spec will only apply to registrations that set one of the given
    // trigger data values (non-negative integers) in the list.
    // trigger_data will still appear in the event-level report.
    "trigger_data": [<int>, ...]

    // Represents a series of time windows, starting at the source registration
    // time. Reports for this spec will be delivered an hour after the end of
    // each window. Time is encoded as seconds after source registration.
    // end_times must consist of strictly increasing positive integers.
    //
    // Note: specs with identical trigger_data cannot have overlapping windows;
    // this ensures that triggers match at most one spec. If
    // event_report_windows is omitted, will use the "event_report_window" or
    // "event_report_windows" field specified at the global level for the source
    // (or the default windows if none are specified). End time is exclusive.
    "event_report_windows": {
      "start_time": <int>,
      "end_times": [<int>, ...],
    }

    // Represents an operator that summarizes the triggers within a window
    // count: number of triggers attributed within a window
    // value_sum: sum of the value of triggers within a window
    // The summary is reported as an index into a bucketization scheme. Defaults
    // to "count"
    "summary_window_operator": <one of "count" or "value_sum">,

    // Represents a bucketization of the integers from [0, MAX_INT], encoded as
    // a list of integers where new buckets begin (excluding 0 which is
    // implicitly included).
    // It must consist of strictly increasing positive integers.
    //
    // e.g. [5, 10, 100] encodes the following ranges:
    // [[0, 4], [5, 9], [10, 99], [100, MAX_INT]]
    //
    // At the end of each reporting window, triggers will be summarized into an
    // integer which slots into one of these ranges. Reports will be sent for
    // every new range boundary that is crossed. Reports will never be sent for
    // the range that includes 0, as every source is initialized in this range.
    //
    // If omitted, then represents a trivial mapping
    // [1, 2, ... , MAX_INT]
    // With MAX_INT being the maximum int value defined by the browser.
    "summary_buckets": [<bucket start>, ...]
  }, {
    // Next trigger_spec
  } ...],

  // See description in phase 1.
  "max_event_level_reports": <int>
  // See description in phase 1.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

این پیکربندی فضای خروجی گزارش‌های سطح رویداد را به‌ازای ثبت منبع، کاملاً مشخص می‌کند. برای هر مشخصات ماشه، ما به طور کامل مشخص می کنیم:

  • مجموعه ای از معیارهای تطبیق:
    • این مشخصات برای کدام داده های ماشه خاص اعمال می شود. این منبع فقط با محرک هایی که یکی از مقادیر trigger_data مشخص شده در trigger_specs را دارند، واجد شرایط مطابقت است. به عبارت دیگر، اگر ماشه با این منبع مطابقت داشت اما trigger_data آن یکی از مقادیر موجود در پیکربندی منبع نباشد، ماشه نادیده گرفته می‌شود.
    • هنگامی که یک ماشه خاص با این مشخصات مطابقت دارد (با استفاده از event_report_windows ). توجه داشته باشید که علیرغم عدم موفقیت در دو معیار تطبیق ذکر شده در بالا، باز هم می‌توان ماشه را با منبعی برای گزارش‌های جمع‌آوری مطابقت داد.
  • یک الگوریتم خاص برای خلاصه کردن و سطل‌بندی تمام محرک‌ها در یک پنجره اسناد. این به تریگرها اجازه می دهد تا پارامتر value را مشخص کنند که برای یک مشخصات خاص خلاصه می شود، اما به عنوان یک مقدار سطلی گزارش می شود.

تریگرها همچنین از افزودن یک پارامتر مقدار اختیاری در فرهنگ لغت در event_trigger_data پشتیبانی می‌کنند.

{
  "event_trigger_data": [
    {
      "trigger_data": "2",
      "value": 100,  // Defaults to 1
      "filters": ...
    },
    ...
  ]
}

هر ثبت ماشه حداکثر با یک مشخصات ماشه مطابقت دارد و مقدار خلاصه مربوط به آن را به روز می کند. در سطح بالا، در زمان شروع ما:

  • فیلترهای ارجاع جهانی را اعمال کنید.
  • برای هر مشخصات ماشه، event_trigger_data را روی مشخصات ارزیابی کنید تا با استفاده از event_reporting_window spec، مطابقت را پیدا کنید. event_reporting_windows سطح بالا به عنوان یک مقدار پیش‌فرض عمل می‌کند در صورتی که هر یک از مشخصات ماشه، قسمت فرعی event_report_windows از دست رفته باشد.
  • اولین مشخصات منطبق برای انتساب انتخاب می‌شود و مقدار خلاصه با value افزایش می‌یابد.

هنگامی که event_report_window برای یک مشخصات کامل شد، مقدار خلاصه آن را به یک سطل نگاشت می‌کنیم، و یک گزارش در سطح رویداد برای هر افزایش در سطل خلاصه ناشی از مقادیر ماشه نسبت داده شده ارسال می‌کنیم. گزارش‌ها با یک فیلد اضافی ارائه می‌شوند، trigger_summary_bucket .

{
  ...
  "trigger_summary_bucket": [<bucket start>, <bucket end>],
}

تنظیماتی که معادل نسخه فعلی هستند

موارد زیر به ترتیب پیکربندی‌های معادل رویداد فعلی و منابع ناوبری APIها هستند. به خصوص برای منابع ناوبری، این نشان می دهد که چرا سطوح نویز نسبت به منابع رویداد بسیار زیاد است تا مقادیر اپسیلون یکسانی حفظ شود: منابع ناوبری فضای خروجی بسیار بزرگتری دارند.

با توجه به اینکه برخی از پارامترها را می توان به عنوان پیش فرض یا هرس کرد، ممکن است چندین پیکربندی معادل وجود داشته باشد.

منابع رویداد معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1],
    "event_report_windows": {
      "end_times": [<30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1],
  }],
  "max_event_level_reports": 1,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}
منابع ناوبری معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3, 4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [<2 days>, <7 days>, <30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3],
  }],
  "max_event_level_reports": 3,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}

نمونه تنظیمات سفارشی

در زیر برخی از تنظیمات اضافی خارج از تنظیمات پیش فرض وجود دارد. در همه این مثال ها، مبادلات توسعه دهنده عبارتند از:

  • کاهش برخی از ابعاد پیکربندی پیش‌فرض (#تریگرها، کاردینالیته داده‌های ماشه، #پنجره‌ها) برای افزایش یکی دیگر برای حفظ سطح نویز
  • کاهش برخی از ابعاد پیکربندی پیش‌فرض (#تریگرها، کاردینالیته داده‌های ماشه، #پنجره‌ها) برای کاهش سطح نویز

سطل‌های مقدار ماشه را گزارش کنید

این پیکربندی مثال از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد داده‌های ارزش را تنها برای یک پنجره گزارش (مثلاً 7 روز) بهینه کند و پنجره‌های گزارش کمتری را با نویز کمتر معامله کند. در این مثال، هر عاملی که trigger_data روی مقداری غیر از 0 تنظیم کند، برای انتساب واجد شرایط نیست.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
    },
    "summary_window_operator": "value_sum",
    "summary_buckets": [5, 10, 100]
  }],
}

تریگرها را می توان با مجموعه فیلد value ثبت کرد که خلاصه و سطل می شود. به عنوان مثال اگر در عرض 7 روز از ثبت منبع با مقادیر 1، 3 و 4، سه تریگر وجود داشته باشد.

{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }

مقادیر به 8 جمع می شوند و پس از 7 روز + 1 ساعت در گزارش های زیر گزارش می شوند:

// Report 1
{
  ...
  "trigger_summary_bucket": [5, 9]
}

در 7 روز بعدی، محرک های زیر ثبت می شوند:

{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }

مقادیر به 8 + 50 + 45 = 103 جمع می شوند. این گزارشات زیر را در 14 روز + 1 ساعت به دست می دهد:

// Report 2
{
  ...
  "trigger_summary_bucket": [10, 99]
},

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
تعداد ماشه ها را گزارش کنید

این مثال نشان می‌دهد که چگونه یک توسعه‌دهنده می‌تواند یک منبع را پیکربندی کند تا تعداد محرک‌ها را تا 10 دریافت کند.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800] // 7 days represented in seconds
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }],
}

محرک‌های منتسب با trigger_data روی 0 شمارش می‌شوند و روی 10 محدود می‌شوند. از آنجایی که summary_window_operator برای شمارش تنظیم شده است، مقدار ماشه نادیده گرفته می‌شود. اگر 4 محرک ثبت شده و به منبع نسبت داده شود، گزارش به شکل زیر خواهد بود:

// Report 1
{
  ...
  "trigger_summary_bucket": [1, 1]
}
// Report 2
{
  ...
  "trigger_summary_bucket": [2, 2]
}
// Report 3
{
  ...
  "trigger_summary_bucket": [3, 3]
}
// Report 4
{
  ...
  "trigger_summary_bucket": [4, 4]
}
باینری با گزارش های مکرر

این پیکربندی مثال از توسعه‌دهنده‌ای پشتیبانی می‌کند که می‌خواهد بداند که آیا حداقل یک تبدیل در 10 روز اول اتفاق افتاده است یا نه (بدون توجه به مقدار)، اما می‌خواهد گزارش‌ها را در فواصل زمانی بیشتر از پیش‌فرض دریافت کند. مجدداً، در این مثال، هر راه‌اندازی که trigger_data روی مقداری غیر از 0 تنظیم کند، برای انتساب واجد شرایط نیست. به همین دلیل است که این مورد استفاده باینری نامیده می شود.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      // 1 day, 2 days, 3 days, 5 days, 7 days, 10 days represented in seconds
      "end_times": [86400, 172800, 259200, 432000, 604800, 864000]
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1]
  }],
}
مشخصات ماشه را از منبعی به منبع دیگر تغییر دهید
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}
{
  "trigger_specs": [
  {
    "trigger_data": [4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}

ما توسعه دهندگان را تشویق می کنیم موارد استفاده متفاوتی را که ممکن است برای این برنامه افزودنی API داشته باشند پیشنهاد کنند، و ما این توضیح دهنده را با پیکربندی های نمونه برای آن موارد استفاده به روز می کنیم.

انتساب شبکه بدون تغییر مسیر

فن‌آوران تبلیغات باید از تغییر مسیرها برای ثبت چندین راه‌انداز منبع انتساب و انجام اسناد بین شبکه‌ای استفاده کنند. این ویژگی به پشتیبانی از انتساب بین شبکه‌ای کمک می‌کند که در آن تغییر مسیرها در سراسر شبکه‌ها امکان‌پذیر نیست. بیشتر بدانید .

فناوری های تبلیغاتی می توانند پیکربندی را در پاسخ ثبت ماشه ارسال کنند که بر اساس آن منابع ثبت شده توسط سایر فناوری های تبلیغاتی برای تولید منابع مشتق شده انتخاب می شوند. این منابع مشتق شده سپس برای انتساب استفاده می شوند. اگر ماشه به یک منبع مشتق شده نسبت داده شود، گزارش‌های انبوه تولید می‌شوند. تولید گزارش رویداد برای منابع مشتق شده پشتیبانی نمی شود.

فناوری‌های تبلیغاتی می‌توانند از میان aggregation_keys در منابع ثبت‌شده خود که قصد دارند با فن‌آوران تبلیغات شریک به اشتراک بگذارند، انتخاب کنند. این کلیدها را می توان در قسمت اختیاری shared_aggregation_keys که در زیر سرصفحه ثبت منبع Attribution-Reporting-Register-Source قرار دارد، اعلام کرد:

"shared_aggregation_keys": ["[key name1]", "[key name2]"]

منابع مشتق شده بر اساس پیکربندی تحت عنوان هدر ثبت ماشه Attribution-Reporting-Register-Trigger تولید می شوند:

  // Specifies the configuration based on which derived sources should be
  // generated. Those derived sources will be included for source matching at the
  // time of attribution. For example, if adtech2 is registering a trigger with an
  // attribution_config with source_network as adtech1, available sources
  // registered by adtech1 will be considered with additional filtering criteria
  // applied to that set as mentioned in the attribution_config. Derived
  // sources can have different values to priority, post_install_exclusivity_window
  // etc.

  "attribution_config": [
    {
      // Derived sources are created from this adtech's registered sources
      "source_network": "[original source's adtech enrollment ID]",
      //(optional) Filter sources whose priority falls in this range
      "source_priority_range": {
        "start": [priority filter lower bound],
        "end": [priority filter upper bound]
      },
      // (optional) Filter sources whose at least one of filter maps matches these
      // filters
      "source_filters": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) Filter sources whose none of filter map matches these
      // filters
        "source_not_filters": {
          "key name 1": ["key1 value 1"]
        },
      // (optional) Apply this priority to the generated derived sources
      "priority": "[64 bit signed integer]",
      // (optional) The derived source will have expiry set as this or parent
      // source's, whichever is earlier
      "expiry": "[64 bit signed integer]",
      // (optional) set on the derived source
      "filter_data": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "[64-bit unsigned integer]"
    }
  ]

در اینجا نسخه ای با مقادیر نمونه اضافه شده است:

  "attribution_config": [
    {
      "source_network": "adtech1-enrollment-id",
      "source_priority_range": {
        "start": 50,
        "end": 100
      },
      "source_filters": {
        "source_type": ["NAVIGATION"]
      },
      "source_not_filters": {
        "product_id": ["789"]
      },
      "priority": "30",
      "expiry": "78901",
      // (optional) set on the derived source
      "filter_data": {
        "product_id": ["1234"]
        },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "7890"
    }
  ]

دو فیلد اختیاری جدید برای شروع هدر ثبت اضافه شده است. این فیلدها شناسه فناوری تبلیغات برنده را در کلیدهای گزارش انبوهی فعال می‌کنند:

  • x_network_bit_mapping : شناسه ثبت نام در نگاشت بیت شناسه فناوری تبلیغات
  • x_network_data : آفست (تغییر به چپ) برای عملیات x_network_bit_mapping OR فناوری تبلیغات برنده با قطعه کلید ماشه
مثال:
"Attribution-Reporting-Register-Trigger": {
  "attribution_config": [...],
  "aggregatable_trigger_data": [
    {
     "key_piece": "0x400",
     "source_keys": ["campaignCounts"]
      "x_network_data" : {
        "key_offset" : 12 // [64 bit unsigned integer]
      }
    }
    …
  ]
  …
  "x_network_bit_mapping": {
   // This mapping is used to generate trigger key pieces with AdTech identifier
   // bits. eg. If AdTechA's sources wins the attribution then 0x1 here will be
   // OR'd with the trigger key pieces to generate the final key piece.
    "AdTechA-enrollment_id": "0x1", // Identifier bits in hex for A
    "AdTechB-enrollment_id": "0x2"  // Identifier bits in hex for B
  }
  …
}

در اینجا محاسبه قطعه کلید ماشه در هنگام ایجاد گزارش برای منبع AdTechB آمده است:

  • key_piece : 0x400 (010000000000)
  • key_offset : 12
  • مقدار enrollment_id AdtechB: 2 (010) (از x_network_bit_mapping )
  • قطعه کلید ماشه نتیجه: 0x400 | 0x2 << 12 = 0x2400

محدودیت ها

برای فهرستی از قابلیت‌های در حال پیشرفت برای زمان اجرا SDK، یادداشت‌های انتشار را مشاهده کنید.

اشکالات و مشکلات را گزارش کنید

بازخورد شما بخش مهمی از جعبه ایمنی حریم خصوصی در Android است! هر مشکلی را که پیدا کردید یا ایده ای برای بهبود Privacy Sandbox در Android به ما اطلاع دهید.

،

همانطور که در اسناد Android Sandbox Privacy می خوانید، از دکمه Developer Preview یا Beta برای انتخاب نسخه برنامه ای که با آن کار می کنید استفاده کنید، زیرا ممکن است دستورالعمل ها متفاوت باشد.


ارائه بازخورد

Attribution Reporting API برای ارائه بهبود حریم خصوصی کاربر با حذف اتکا به شناسه‌های کاربر بین حزبی و پشتیبانی از موارد استفاده کلیدی برای اندازه‌گیری اسناد و تبدیل در بین برنامه‌ها طراحی شده است. این راهنمای توسعه‌دهنده نحوه پیکربندی و آزمایش APIهای گزارش Attribution را برای ثبت کلیک‌ها، بازدیدها و تبدیل‌های تبلیغاتی با فراخوانی روش‌هایی که محرک‌ها و منابع مربوطه را برای چنین رویدادهایی ثبت می‌کنند، شرح می‌دهد.

این راهنما به شما می آموزد که چگونه نقاط پایانی سرور را تنظیم کنید و یک برنامه مشتری بسازید که این خدمات را فراخوانی کند. درباره طراحی کلی Attribution Reporting API در طرح پیشنهادی بیشتر بیاموزید.

شرایط کلیدی

  • منابع انتساب به کلیک ها یا بازدیدها اشاره دارد.
  • محرک ها رویدادهایی هستند که می توانند به تبدیل ها نسبت داده شوند.
  • گزارش‌ها حاوی داده‌هایی درباره یک ماشه و منبع انتساب مربوطه هستند. این گزارش ها در پاسخ به رویدادهای محرک ارسال می شوند. Attribution Reporting API از گزارش‌های سطح رویداد و گزارش‌های جمع‌آوری‌شده پشتیبانی می‌کند.

قبل از اینکه شروع کنی

برای استفاده از Attribution Reporting API، وظایف سمت سرور و سمت سرویس گیرنده فهرست شده در بخش‌های زیر را تکمیل کنید.

نقاط پایانی API Reporting Attribution را تنظیم کنید

Attribution Reporting API به مجموعه‌ای از نقاط پایانی نیاز دارد که می‌توانید از دستگاه آزمایشی یا شبیه‌ساز به آنها دسترسی داشته باشید. برای هر یک از وظایف سمت سرور زیر یک نقطه پایانی ایجاد کنید:

چندین روش برای تنظیم نقاط پایانی مورد نیاز وجود دارد:

  • سریع ترین راه برای راه اندازی و اجرا، استقرار تعاریف سرویس OpenAPI v3 از مخزن کد نمونه ما در یک پلت فرم ساختگی یا میکروسرویس است. می توانید از Postman ، Prism یا هر پلتفرم سرور ساختگی دیگری که این قالب را می پذیرد استفاده کنید. هر نقطه پایانی را مستقر کنید و URI ها را برای استفاده در برنامه خود پیگیری کنید. برای تأیید تحویل گزارش، به تماس‌هایی که قبلاً با پلتفرم ساختگی یا بدون سرور برقرار شده است مراجعه کنید.
  • سرور مستقل خود را با استفاده از نمونه Kotlin مبتنی بر Spring Boot اجرا کنید. این سرور را در ارائه دهنده ابر یا زیرساخت داخلی خود مستقر کنید.
  • از تعاریف سرویس به عنوان مثال برای ادغام نقاط پایانی در سیستم موجود خود استفاده کنید.

پذیرش ثبت منبع

این نقطه پایانی باید از یک URI مشابه زیر قابل آدرس دهی باشد:

https://adtech.example/attribution_source

هنگامی که یک برنامه مشتری یک منبع انتساب را ثبت می کند ، URI را برای این نقطه پایانی سرور ارائه می دهد. سپس Attribution Reporting API درخواستی می دهد و یکی از سرصفحه های زیر را شامل می شود:

  • برای رویدادهای کلیک کنید:

    Attribution-Reporting-Source-Info: navigation
    
  • برای مشاهده رویدادها:

    Attribution-Reporting-Source-Info: event
    

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهد:

// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  // Attribution source metadata specifying histogram contributions in aggregate
  // report.
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  },

    "debug_key": "[64-bit unsigned integer]",
    "debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا یک مثال با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Source: {
  "destination": "android-app://com.example.advertiser",
  "source_event_id": "234",
  "expiry": "259200",
  "event_report_window": "172800",
  "aggregatable_report_window": "172800",
  "priority": "5",
  "filter_data": {
    "product_id": ["1234"]
  },
  "aggregation_keys": {
  // Generates a "0x159" key piece named (low order bits of the key) for the key
  // named "campaignCounts".
  // User saw an ad from campaign 345 (out of 511).
    "campaignCounts": "0x159",

  // Generates a "0x5" key piece (low order bits of the key) for the key named
  // "geoValue".
  // Source-side geo region = 5 (US), out of a possible ~100 regions.
    "geoValue": "0x5",
  },
  // Opts in to receiving verbose debug reports
  "debug_reporting": true
}

Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890

اگر Attribution-Reporting-Redirects شامل URI شرکای فناوری تبلیغات باشد، API گزارش Attribution درخواست مشابهی را برای هر URI ارسال می کند. هر شریک فناوری تبلیغاتی باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  }
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

ثبت نام ماشه تبدیل را بپذیرید

این نقطه پایانی باید از یک URI مشابه زیر قابل آدرس دهی باشد:

https://adtech.example/attribution_trigger

هنگامی که یک برنامه مشتری یک رویداد ماشه را ثبت می کند ، URI را برای این نقطه پایانی سرور ارائه می دهد. سپس Attribution Reporting API درخواستی می دهد و یکی از سرصفحه های زیر را شامل می شود:

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data returned" in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // "filter" and "not_filters" are optional fields which allow configuring
    // event trigger data based on source's filter_data. They consist of a
    // filter set, which is a list of filter maps. An event_trigger_data object
    // is ignored if none of the filter maps in the set match the source's
    // filter data.
    // Note: "source_type" can be used as a key in a filter map to filter based
    // on the source's "navigation" or "event" type. The first
    // Event-Trigger that matches (based on the filters/not_filters) will be
    // used for report generation. If none of the event-triggers match, no
    // event report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it won't be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it won't
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  // Specify a list of dictionaries that generates aggregation keys.
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]]
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16]
  // to contribute to each key that is attached to aggregation keys in the
  // order they are generated.
  "aggregatable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the
     // aggregate histogram.
    {
     "[key_name]": [value]
    },
    ..
  ],
  aggregatable_deduplication_keys: [{
  deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_H]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
  },
  ...
  {
  "deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_D]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
    }
  ]

  "debug_key": "[64-bit unsigned integer]",
  "debug_reporting": [boolean]

}
// Specify additional ad tech URLs to register this trigger with.
// Repeated Header field "Attribution-Reporting-Redirect"
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا یک مثال با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    "trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["event"]
    }]
  },
  {
    "trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["navigation"]
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary independently adds pieces to multiple source keys.
    {
      // Conversion type purchase = 2 at a 9-bit offset, i.e. 2 << 9.
      // A 9-bit offset is needed because there are 511 possible campaigns,
      // which takes up 9 bits in the resulting key.
      "key_piece": "0x400",// Conversion type purchase = 2
      // Apply this key piece to:
      "source_keys": ["campaignCounts"]
       // Filter strings can not exceed 25 characters
    },
    {
      // Purchase category shirts = 21 at a 7-bit offset, i.e. 21 << 7.
      // A 7-bit offset is needed because there are ~100 regions for the geo
      // key, which takes up 7 bits of space in the resulting key.
      "key_piece": "0xA80",
      // Apply this key piece to:
      "source_keys": ["geoValue", "nonMatchingIdsAreIgnored"]
      // source_key values must not exceed the limit of 25 characters
    }
  ],
  "aggregatable_values":
    {
      // Privacy budget for each key is L1 / 2 = 2^15 (32768).
      // Conversion count was 1.
      // Scale the count to use the full budget allocated: 1 * 32768 = 32768.
      "campaignCounts": 32768,

      // Purchase price was $52.
      // Purchase values for the app range from $1 to $1,024 (integers only).
      // Scaling factor applied is 32768 / 1024 = 32.
      // For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
      "geoValue": 1664
    }
  ,
  // aggregatable_deduplication_keys is an optional field. Up to 50 "keys"
  // can be included in the aggregatable_deduplication_keys list. Filters, not
  // filters, and deduplication_key are optional fields. If deduplication_key
  // is omitted, it will be treated as a null value. See
  // https://wicg.github.io/attribution-reporting-api/#triggering-aggregatable-attribution
  aggregatable_deduplication_keys:
  [
    {
    deduplication_key": 3,
        "filters": {
          "category": [A]
        }
    },
    {
    "deduplication_key": 4,
        "filters": {
          "category": [C, D]
        },
        "not_filters": {
          "category": [F]
        }
    }
  ]
  // Opts into receiving verbose debug reports
  "debug_reporting": true
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567

محدودیت 25 بایت برای هر شناسه کلید تجمعی و رشته فیلتر وجود دارد. این بدان معناست که شناسه‌های کلید تجمعی و رشته‌های فیلتر نباید از ۲۵ کاراکتر تجاوز کنند. در این مثال، campaignCounts 14 کاراکتر است، بنابراین یک شناسه کلید تجمعی معتبر است، و 1234 4 کاراکتر است، بنابراین یک رشته فیلتر معتبر است. اگر شناسه کلید تجمیع یا رشته فیلتر بیش از 25 کاراکتر باشد، ماشه نادیده گرفته می شود.

اگر Attribution-Reporting-Redirect شامل URI شرکای فناوری تبلیغات باشد، API گزارش Attribution درخواست مشابهی را برای هر URI ارسال می کند. هر شریک فناوری تبلیغاتی باید سروری را پیکربندی کند که با این هدرها پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data" returned in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // filter and not_filters are optional fields which allow configuring
    // different event trigger data based on source's filter_data. They
    // consist of a filter set, which is a list of filter maps. An
    // event_trigger_data object is ignored if none of the filter maps in the
    // set match the source's filter data. Note: "source_type" can be used as
    // a key in a filter map to filter based on the source's "navigation" or
    // "event" type. The first Event-Trigger that matches (based on the
    // filters/not_filters) will be used for report generation. If none of the
    // event-triggers match, no report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it will not be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it will not
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]],
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16] to
  // contribute to each key that is attached to aggregation keys in the order they
  // are generated.
  "aggregatable_values": [
    // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
    // histogram.
    {
     "[key_name]": [value]
    }
  ]
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

گزارش های سطح رویداد را بپذیرید

این نقطه پایانی باید از یک URI آدرس دهی شود. برای کسب اطلاعات بیشتر در مورد ثبت نام URIS ، به ثبت نام در حساب Sandbox حریم خصوصی مراجعه کنید. . _

https://adtech.example/.well-known/attribution-reporting/report-event-attribution

این سرور را پیکربندی کنید تا درخواست های JSON را که از قالب زیر استفاده می کنند ، بپذیرید:

{
  "attribution_destination": "android-app://com.advertiser.example",
  "source_event_id": "12345678",
  "trigger_data": "2",
  "report_id": "12324323",
  "source_type": "navigation",
  "randomized_trigger_rate": "0.02"
   [Optional] "source_debug_key": "[64-bit unsigned integer]",
   [Optional] "trigger_debug_key": "[64-bit unsigned integer]",
}

کلیدهای اشکال زدایی امکان بینش اضافی در مورد گزارش های انتساب شما را فراهم می کند. در مورد پیکربندی آنها بیشتر بدانید .

گزارش های قابل جمع را بپذیرید

این نقطه پایانی باید از URI قابل پرداخت باشد. برای کسب اطلاعات بیشتر در مورد ثبت نام URIS ، به ثبت نام در حساب Sandbox حریم خصوصی مراجعه کنید. . _

https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution

هر دو زمینه رمزگذاری شده و بدون رمزگذاری برای گزارش های قابل جمع شدن جمع می شوند. گزارش های رمزگذاری شده شما را قادر می سازد تا با سرویس جمع آوری آزمایش را شروع کنید ، در حالی که زمینه رمزگذاری نشده بینشی را در مورد نحوه تنظیم جفت های ارزش کلید در حال ساخت داده ها فراهم می کند.

این سرور را پیکربندی کنید تا درخواست های JSON را که از قالب زیر استفاده می کنند ، بپذیرید:

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform does not yet encrypt aggregate reports.
  // Currently, the "debug_cleartext_payload" field holds unencrypted reports.
  "aggregation_service_payloads": [
    {
      "payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
      "key_id": "[string identifying public key used to encrypt payload]",

      "debug_cleartext_payload": "[unencrypted payload]"
    },
  ],

  "source_debug_key": "[64 bit unsigned integer]",
  "trigger_debug_key": "[64 bit unsigned integer]"
}

کلیدهای اشکال زدایی امکان بینش اضافی در مورد گزارش های انتساب شما را فراهم می کند. در مورد پیکربندی آنها بیشتر بدانید .

مشتری Android را تنظیم کنید

برنامه مشتری منابع انتساب و محرک را ثبت می کند و تولید گزارش سطح و قابل جمع شدن را امکان پذیر می کند. برای تهیه یک دستگاه یا شبیه ساز مشتری Android برای استفاده از API گزارش انتساب ، موارد زیر را انجام دهید:

  1. محیط توسعه خود را برای ماسهبازی حریم خصوصی در Android تنظیم کنید .
  2. یک تصویر سیستم را روی یک دستگاه پشتیبانی شده نصب کنید یا یک شبیه ساز را تنظیم کنید که شامل پشتیبانی از جعبه ماسه حریم خصوصی در Android باشد.
  3. با اجرای دستور ADB زیر ، دسترسی به API گزارش انتساب را فعال کنید . (API به طور پیش فرض غیرفعال است.)

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
    
  4. اگر به صورت محلی در حال آزمایش API گزارش انتساب (مانند آزمایش بر روی دستگاهی هستید که به جسمی دسترسی دارید) ، این دستور را برای غیرفعال کردن ثبت نام اجرا کنید:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
    
  5. مجوز ACCESS_ADSERVICES_ATTRIBUTION را در پرونده مانیفست Android خود قرار دهید و یک پیکربندی خدمات تبلیغاتی را برای برنامه خود ایجاد کنید تا از API های گزارشگری Attribution استفاده کنید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (اختیاری) اگر قصد دریافت گزارش های اشکال زدایی را دارید ، مجوز ACCESS_ADSERVICES_AD_ID را در پرونده مانیفست اندرویدی خود قرار دهید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. پیکربندی خدمات تبلیغاتی را در عنصر <application> مانیفست خود ارجاع دهید:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. خدمات AD Services XML را که در مانیفست ارجاع شده است ، مانند res/xml/ad_services_config.xml مشخص کنید. در مورد مجوزهای خدمات تبلیغاتی و کنترل دسترسی SDK بیشتر بدانید.

    <ad-services-config>
        <attribution allowAllToAccess="true" />
    </ad-services-config>
    

ثبت رویدادهای تبلیغاتی

برنامه شما باید منابع و تبدیل ها را به عنوان اتفاق بیفتد تا اطمینان حاصل شود که به درستی گزارش شده است. کلاس MeasurementManager روش هایی را برای کمک به شما در ثبت وقایع منبع انتساب و محرک های تبدیل به شما کمک می کند.

یک رویداد منبع انتساب را ثبت کنید

هنگامی که یک آگهی مشاهده یا کلیک می شود ، یک برنامه ناشر برای ثبت نام منبع انتساب همانطور که در قطعه کد نشان داده شده است ، با ثبت registerSource() تماس می گیرد.

API گزارش انتساب از انواع زیر از رویدادهای منبع انتساب پشتیبانی می کند:

  • کلیک ، که شما به طور معمول در یک روش پاسخ به تماس مشابه با onClick() ثبت می کنید. رویداد ماشه مربوطه معمولاً به زودی پس از رویداد کلیک اتفاق می افتد. این نوع رویداد اطلاعات بیشتری در مورد تعامل کاربر ارائه می دهد و بنابراین نوع خوبی از منبع انتساب برای اولویت بالایی است.
  • بازدیدها ، که شما به طور معمول در یک روش پاسخ به تماس مشابه با onAdShown() ثبت می کنید. رویداد ماشه مربوطه ممکن است ساعات یا چند روز پس از رویداد مشاهده رخ دهد.

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
  Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
    exampleClickEvent = event
    true
}

// Register Click Event
measurementManager.registerSource(
        attributionSourceUri,
        exampleClickEvent,
        CALLBACK_EXECUTOR,
        future::complete)

// Register View Event
measurementManager.registerSource(
        attributionSourceUri,
        null,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
Uri attributionSourceUri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event)) -> {
    exampleClickEvent = event;
    return true;
}

// Register Click Event
measurementManager.registerSource(attributionSourceUri, exampleClickEvent,
        CALLBACK_EXECUTOR, future::complete);

// Register View Event
measurementManager.registerSource(attributionSourceUri, null,
        CALLBACK_EXECUTOR, future::complete);

پس از ثبت نام ، API درخواست HTTP Post را به نقطه پایانی سرویس در آدرس مشخص شده توسط attributionSourceUri صادر می کند. پاسخ نقطه پایانی شامل مقادیر destination, source_event_id, expiry و source_priority است.

اگر فناوری تبلیغاتی مبداء بخواهد ثبت نام های منبع را به اشتراک بگذارد ، منبع اصلی انتساب URI می تواند شامل تغییر مسیر به سایر نقاط پایانی فناوری باشد. محدودیت ها و قوانینی که در مورد تغییر مسیر اعمال می شود ، در پیشنهاد فنی به تفصیل شرح داده شده است.

پشتیبانی برای تغییر مسیر زنجیره دیزی برای registerSource و registerTrigger اضافه شده است. علاوه بر عنوان ثبت نام ، مصرف کننده API هم اکنون می تواند HTTP را به عنوان پاسخ سرور که شامل یک کد وضعیت 302 و یک هدر "مکان" با URL بعدی برای بازدید برای ثبت نام اضافی است ، ارائه دهد.

فقط قسمت "مقصد" ارائه شده در اولین بازدید در سراسر زنجیره دیزی استفاده می شود. تعداد بازدیدها همان حد را با عنوان های "انتساب-گزارشگر-REDIRECT" دارد. این پشتیبانی تغییر مسیر علاوه بر پشتیبانی موجود "انتساب-گزارشگر-REDIRECT" موجود است و اگر هر دو وجود داشته باشند ، "انتساب-گزارشگر-REDIRECT" اولویت می گیرد.

یک رویداد ماشه تبدیل را ثبت کنید

برای ثبت یک رویداد ماشه تبدیل ، با registerTrigger() در برنامه خود تماس بگیرید:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
    Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts trigger registration.
Uri attributionTriggerUri =
        Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

پس از ثبت نام ، API درخواست HTTP Post را به نقطه پایانی سرویس در آدرس مشخص شده توسط attributionTriggerUri صادر می کند. پاسخ نقطه پایانی شامل مقادیر گزارش های رویداد و کل است.

اگر بستر تبلیغاتی AD Tech اجازه می دهد تا ثبت نام های ماشه به اشتراک گذاشته شود ، URI می تواند شامل تغییر مسیر به URI ها باشد که متعلق به سایر سیستم عامل های AD Tech است. محدودیت ها و قوانینی که در مورد تغییر مسیر اعمال می شود ، در پیشنهاد فنی به تفصیل شرح داده شده است.

ثبت نام برنامه و اندازه گیری وب را ثبت کنید

در موردی که هم یک برنامه و هم مرورگر در سفر کاربر از منبع به تحریک نقش داشته باشند ، تفاوت های ظریف در اجرای ثبت نام رویدادهای تبلیغاتی وجود دارد. اگر کاربر تبلیغی را در یک برنامه مشاهده کند و برای تبدیل به یک مرورگر هدایت شود ، منبع توسط برنامه ثبت شده و تبدیل توسط مرورگر وب است. به همین ترتیب ، اگر کاربر از یک مرورگر وب شروع کند و برای تبدیل به یک برنامه هدایت شود ، مرورگر منبع را ثبت می کند و برنامه تبدیل را ثبت می کند.

از آنجا که تفاوت هایی در نحوه سازماندهی فناوری های تبلیغاتی در وب و Android وجود دارد ، ما API های جدیدی را برای ثبت منابع و محرک ها در هنگام انجام آنها در مرورگرها اضافه کرده ایم. تفاوت اصلی بین این API ها و API های مبتنی بر برنامه مربوطه در این است که ما انتظار داریم مرورگر از تغییر مسیر پیروی کند ، از هر فیلترهای خاص مرورگر استفاده کند و با فراخوانی registerWebSource() یا registerWebTrigger() ثبت نام های معتبر را به سیستم عامل منتقل کند.

قطعه کد زیر نمونه ای از تماس API را نشان می دهد که مرورگر قبل از هدایت کاربر به یک برنامه ، یک منبع انتساب را ثبت می کند:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager =
        context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
val sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build()

val sourceParams = Arrays.asList(sourceParam1, sourceParam2, sourceParam3)
val publisherOrigin = Uri.parse("https://publisher.example")
val appDestination = Uri.parse("android-app://com.example.store")
val webDestination = Uri.parse("https://example.com")

val future = CompletableFuture<Void>()

adView.setOnTouchListener {_: View?, event: MotionEvent? ->
    exampleClickEvent = event
    true
}
val clickRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(event)
      .build()
val viewRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(null)
      .build()

// Register a web source for a click event.
measurementManager.registerWebSource(
        clickRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

// Register a web source for a view event.
measurementManager.registerWebSource(
        viewRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
WebSourceParams sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebSourceParams sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

WebSourceParams sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build();

List<WebSourceParams> sourceParams =
        Arrays.asList(sourceParam1, sourceParam2, sourceParam3);
Uri publisherOrigin = Uri.parse("https://publisher.example");
Uri appDestination = Uri.parse("android-app://com.example.store");
Uri webDestination = Uri.parse("https://example.com");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event) -> {
    exampleClickEvent = event;
    return true;
}

WebSourceRegistrationRequest clickRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(event)
    .build();
WebSourceRegistrationRequest viewRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(null)
    .build();

// Register a web source for a click event.
measurementManager.registerWebSource(clickRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

// Register a web source for a view event.
measurementManager.registerWebSource(viewRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

قطعه کد زیر نمونه ای از تماس API را نشان می دهد که مرورگر برای ثبت یک تبدیل پس از کارگردانی کاربر از برنامه ایجاد می کند:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URIs of the server-side endpoints that accept trigger registration.
val triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val triggerParams = Arrays.asList(triggerParam1, triggerParam2)
val advertiserOrigin = Uri.parse("https://advertiser.example")

val future = CompletableFuture<Void>()

val triggerRegistrationRequest = WebTriggerRegistrationRequest.Builder(
        triggerParams,
        advertiserOrigin)
    .build()

// Register the web trigger (conversion).
measurementManager.registerWebTrigger(
    triggerRegistrationRequest,
    CALLBACK_EXECUTOR,
    future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept trigger registration.
WebTriggerParams triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebTriggerParams triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

List<WebTriggerParams> triggerParams =
        Arrays.asList(triggerParam1, triggerParam2);
Uri advertiserOrigin = Uri.parse("https://advertiser.example");

CompletableFuture<Void> future = new CompletableFuture<>();

WebTriggerRegistrationRequest triggerRegistrationRequest =
        new WebTriggerRegistrationRequest.Builder(
            triggerParams, advertiserOrigin)
    .build();

// Register the web trigger (conversion).
measurementManager.registerWebTrigger( triggerRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

اضافه کردن نوآوری برای حریم خصوصی

گزارش های سطح رویداد حاوی مقصد ، شناسه منبع انتساب و داده های ماشه است. آنها در قالب اصلی (رمزگذاری نشده) به مبدا گزارش ارسال می شوند. برای محافظت از حریم خصوصی کاربر ، می توان سر و صدای اضافه کرد تا شناسایی یک کاربر فردی دشوارتر شود. گزارش های سطح رویداد Noised مطابق با چارچوب نهیاری دیفرانسیل تولید و ارسال می شوند. این مقادیر پیش فرض درصد نویز برای سناریوهای مختلف است:

نوع منبع

مقدار مقصد مقصد

احتمال گزارش بدون ثبت در هر منبع ثبت نام

چشم انداز

یا برنامه یا وب

0.0000025

چشم انداز

برنامه و وب

0.0000042

کلیک

یا برنامه یا وب

0.0024263

کلیک

برنامه و وب

0.0170218

در اندازه گیری انتساب برنامه به WEB ، که در آن منابع می توانند به هر دو برنامه و مقصد وب تبدیل شوند ، گزارش های سطح رویداد می توانند مشخص کنند که آیا ماشه در برنامه یا وب رخ داده است. برای جبران این جزئیات اضافی ، گزارش های Noised تولید شده تا 7 برابر برای کلیک و 1.7 برابر پوند برای نماها است.

برخی از فناوری های تبلیغاتی برای مشخص کردن اینکه آیا ماشه در برنامه یا مقصد وب رخ داده است ، نیازی به گزارش های سطح رویداد ندارند. فناوری های تبلیغاتی می توانند از قسمت coarse_event_report_destinations تحت عنوان Attribution-Reporting-Register-Source برای کاهش نویز استفاده کنند. اگر یک منبع با قسمت coarse_event_report_destinations مشخص شده برنده شده باشد ، گزارش حاصل شامل برنامه و مقصد وب بدون تمایز در مورد اینکه ماشه واقعی در کجا رخ داده است.

در مثالهای زیر ، کاربر روی یک تبلیغ کلیک می کند و آن منبع در API ثبت می شود. کاربر سپس به برنامه تبلیغ کننده و وب سایت تبلیغ کننده تبدیل می کند. هر دو این تبدیل به عنوان محرک ثبت شده و به کلیک اولیه نسبت داده می شوند.

ثبت نام منبع مبتنی بر کلیک هدر HTTP:

Attribution-Reporting-Register-Source: {
    "destination": "android-app://com.advertiser.example",
    "web_destination": "https://advertiser.com",
    "source_event_id": "234",
    "expiry": "60000",
    "priority": "5",
    // Ad tech opts out of receiving app-web destination distinction
    // in event report, avoids additional noise
    "coarse_event_report_destinations": "true"
}

یک ماشه از برنامه با نام بسته com.advertiser.example ثبت شده است:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "1",
    "priority": "1"
    }],
}

یک ماشه از یک مرورگر از وب سایت با دامنه ETLD+1 https://advertiser.com ثبت شده است:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "2",
    "priority": "2"
    }],
}

گزارش های سطح رویداد حاصل می شود. با فرض اینکه هر دو محرک به منبع نسبت داده می شوند ، گزارش های سطح رویداد زیر تولید می شوند:

  {
    "attribution_destination": ["android-app://com.advertiser.example,https://advertiser.com"],
    "scheduled_report_time": "800176400",
    "source_event_id": "53234",
    "trigger_data": "1",
    // Can be "event" if source were registered by user viewing the ad
    "source_type": "navigation",
    // Would be 0.0170218 without coarse_event_report_destinations as true in the source
    "randomized_trigger_rate": 0.0024263
  }

گزارش ها را تهیه و ارائه دهید

API گزارشگر انتساب گزارش ها را به نقاط پایانی روی سرور شما ارسال می کند که گزارش های سطح رویداد و گزارش های قابل جمع را می پذیرند.

مشاغل گزارش دهی را برای اجرا مجبور کنید

پس از ثبت یک رویداد منبع Attribution یا یک رویداد ماشه را ثبت کنید ، سیستم برنامه گزارش دهی را برنامه ریزی می کند. به طور پیش فرض ، این کار هر 4 ساعت یکبار انجام می شود. برای اهداف آزمایش ، می توانید مشاغل گزارش دهی را مجبور به اجرای یا کوتاه کردن فواصل بین مشاغل کنید.

کار انتساب نیرو برای اجرای:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 5

کار گزارش در سطح رویداد را برای اجرای:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 3

کار گزارشگری قابل جمع شدن را به اجرا درآورد:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 7

خروجی موجود در LogCat را بررسی کنید تا ببینید چه موقع کار انجام شده است. باید چیزی شبیه به زیر باشد:

JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true

تحویل گزارش ها

حتی اگر کار گزارشگری مجبور به اجرای آن شود ، سیستم هنوز گزارش هایی را با توجه به زمان تحویل برنامه ریزی شده خود ارسال می کند ، که از چند ساعت تا چند روز متغیر است. برای اهداف آزمایش ، می توانید زمان سیستم دستگاه را پس از تأخیرهای برنامه ریزی شده برای شروع تحویل گزارش پیش ببرید.

گزارش های مربوط به سرور خود را تأیید کنید

پس از ارسال گزارش ها ، تحویل را با بررسی گزارش های دریافت شده ، گزارش های سرور قابل اجرا مانند تاریخچه سرور Mock یا سیستم سفارشی خود تأیید کنید.

گزارش کل خود را رمزگشایی کنید

هنگام دریافت گزارش کل ، قسمت debug_cleartext_payload یک نسخه رمزگذاری نشده از گزارش کل شما را در خود جای داده است. در حالی که این نسخه از گزارش شما رمزگذاری نشده است ، هنوز هم باید رمزگشایی شود.

در زیر نمونه ای از رمزگشایی محتوای قسمت debug_cleartext_payload در دو مرحله وجود دارد: اولین با استفاده از رمزگشایی پایه 64 و دوم با استفاده از رمزگشایی CBOR.

String base64DebugPayload  = "omRkYXRhgqJldmFsdWVEAAAGgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAKhaJldmFsdWVEAACAAGZidWNrZXRQAAAAAAAAAAAAAAAAAAAFWWlvcGVyYXRpb25paGlzdG9ncmFt";
byte[] cborEncoded = Base64.getDecoder().decode(base64DebugPayload);

// CbodDecoder comes from this library https://github.com/c-rack/cbor-java
final List<DataItem> dataItems = new CborDecoder(new ByteArrayInputStream(cborEncoded)).decode();

// In here you can see the contents, but the value will be something like:
// Data items: [{ data: [{ value: co.nstant.in.cbor.model.ByteString@a8b5c07a,
//   bucket: co.nstant.in.cbor.model.ByteString@f812097d },
//   { value: co.nstant.in.cbor.model.ByteString@a8b5dfc0,
//   bucket: co.nstant.in.cbor.model.ByteString@f8120934 }], operation: histogram }]
Log.d("Data items : " + dataItems);

// In order to see the value for bucket and value, you can traverse the data
// and get their values, something like this:
final Map payload = (Map) dataItems.get(0);
final Array payloadArray = (Array) payload.get(new UnicodeString("data"));

payloadArray.getDataItems().forEach(i -> {
    BigInteger value = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("value"))).getBytes());
    BigInteger bucket = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("bucket"))).getBytes());
    Log.d("value : " + value + " ;bucket : " + bucket);
});

آزمایش کردن

برای کمک به شما در شروع کار با API گزارش انتساب ، می توانید از پروژه اندازه گیری AMPLEAPP در GitHub استفاده کنید. این برنامه نمونه ثبت نام منبع انتساب و ثبت نام را نشان می دهد.

برای نقاط پایانی سرور ، منابع مرجع زیر یا راه حل سفارشی خود را در نظر بگیرید:

  • اندازه گیری adtechserverspec شامل تعاریف سرویس OpenAPI است ، که می تواند به یک سیستم عامل مسخره یا میکروسرویس پشتیبانی شود.
  • اندازه گیری adtechserver شامل اجرای مرجع یک سرور مسخره بر اساس برنامه Boot Spring برای Google App Engine است.

پیش نیازها

API های مسخره را در نقاط پایانی از راه دور که از دستگاه تست یا شبیه ساز خود قابل دسترسی است ، مستقر کنید. برای سهولت در آزمایش ، به پروژه های نمونه SeasureAdtechserverspec و اندازه گیری adtechserver مراجعه کنید.

عملکرد برای آزمایش

ویژگی های آینده

پیکربندی سطح رویداد انعطاف پذیر

پیکربندی پیش فرض برای گزارش سطح رویداد برای شروع آزمایش ابزار توصیه شده است ، اما ممکن است برای همه موارد استفاده ایده آل نباشد. API گزارشگر انتساب از تنظیمات اختیاری و انعطاف پذیر تر پشتیبانی می کند به طوری که تکنیک های تبلیغاتی کنترل ساختار گزارش های سطح رویداد خود را افزایش داده و قادر به به حداکثر رساندن کاربرد داده ها هستند. این انعطاف پذیری اضافی در دو مرحله به API گزارش انتساب معرفی می شود:

  • فاز 1 : پیکربندی سطح رویداد انعطاف پذیر Lite ؛ زیر مجموعه فاز 2.
  • فاز 2 : نسخه کامل پیکربندی سطح رویداد انعطاف پذیر.

فاز 1: سطح رویداد انعطاف پذیر Lite

ما دو پارامتر اختیاری زیر را به JSON در Attribution-Reporting-Register-Source اضافه خواهیم کرد:

  • max_event_level_reports
  • event_report_windows
{
  ...
  // Optional. This is a parameter that acts across all trigger types for the
  // lifetime of this source. It restricts the total number of event-level
  // reports that this source can generate. After this maximum is hit, the
  // source is no longer capable of producing any new data. The use of
  // priority in the trigger attribution algorithm in the case of multiple
  // attributable triggers remains unchanged. Defaults to 3 for navigation
  // sources and 1 for event sources
  "max_event_level_reports": <int>,

  // Optional. Represents a series of time windows, starting at 0. Reports
  // for this source will be delivered an hour after the end of each window.
  // Time is encoded as seconds after source registration. If
  // event_report_windows is omitted, will use the default windows. This
  // field is mutually exclusive with the existing `event_report_window` field.
  // // End time is exclusive.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

مثال پیکربندی سفارشی

این پیکربندی مثال از یک توسعه دهنده پشتیبانی می کند که می خواهد برای دریافت گزارش در ویندوزهای گزارش قبلی بهینه شود.

{
  ...
  "max_event_level_reports": 2,
  "event_report_windows": {
    "end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
  }
}

فاز 2: سطح کامل رویداد انعطاف پذیر

علاوه بر پارامترهایی که در فاز 1 اضافه شده اند ، ما یک پارامتر اختیاری اضافی trigger_specs را به JSON در Attribution-Reporting-Register-Source اضافه خواهیم کرد.

{
  // A trigger spec is a set of matching criteria, along with a scheme to
  // generate bucketized output based on accumulated values across multiple
  // triggers within the specified event_report_window. There will be a limit on
  // the number of specs possible to define for a source.
  "trigger_specs": [{
    // This spec will only apply to registrations that set one of the given
    // trigger data values (non-negative integers) in the list.
    // trigger_data will still appear in the event-level report.
    "trigger_data": [<int>, ...]

    // Represents a series of time windows, starting at the source registration
    // time. Reports for this spec will be delivered an hour after the end of
    // each window. Time is encoded as seconds after source registration.
    // end_times must consist of strictly increasing positive integers.
    //
    // Note: specs with identical trigger_data cannot have overlapping windows;
    // this ensures that triggers match at most one spec. If
    // event_report_windows is omitted, will use the "event_report_window" or
    // "event_report_windows" field specified at the global level for the source
    // (or the default windows if none are specified). End time is exclusive.
    "event_report_windows": {
      "start_time": <int>,
      "end_times": [<int>, ...],
    }

    // Represents an operator that summarizes the triggers within a window
    // count: number of triggers attributed within a window
    // value_sum: sum of the value of triggers within a window
    // The summary is reported as an index into a bucketization scheme. Defaults
    // to "count"
    "summary_window_operator": <one of "count" or "value_sum">,

    // Represents a bucketization of the integers from [0, MAX_INT], encoded as
    // a list of integers where new buckets begin (excluding 0 which is
    // implicitly included).
    // It must consist of strictly increasing positive integers.
    //
    // e.g. [5, 10, 100] encodes the following ranges:
    // [[0, 4], [5, 9], [10, 99], [100, MAX_INT]]
    //
    // At the end of each reporting window, triggers will be summarized into an
    // integer which slots into one of these ranges. Reports will be sent for
    // every new range boundary that is crossed. Reports will never be sent for
    // the range that includes 0, as every source is initialized in this range.
    //
    // If omitted, then represents a trivial mapping
    // [1, 2, ... , MAX_INT]
    // With MAX_INT being the maximum int value defined by the browser.
    "summary_buckets": [<bucket start>, ...]
  }, {
    // Next trigger_spec
  } ...],

  // See description in phase 1.
  "max_event_level_reports": <int>
  // See description in phase 1.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

این پیکربندی به طور کامل فضای خروجی گزارش های سطح رویداد ، در هر ثبت منبع را مشخص می کند. برای هر مشخصات ماشه ، ما کاملاً مشخص می کنیم:

  • مجموعه ای از معیارهای تطبیق:
    • این مشخصات مربوط به کدام یک از داده های خاص است. این منبع واجد شرایط است که فقط با محرک هایی که یکی از مقادیر trigger_data مشخص شده در trigger_specs دارند ، مطابقت دارد. به عبارت دیگر ، اگر ماشه با این منبع مطابقت داشته باشد اما trigger_data آن یکی از مقادیر موجود در پیکربندی منبع نیست ، ماشه نادیده گرفته می شود.
    • هنگامی که یک ماشه خاص با این مشخصات مطابقت دارد (با استفاده از event_report_windows ). توجه داشته باشید که این ماشه با وجود عدم موفقیت در معیارهای دو مسابقه که قبلاً ذکر شد ، می تواند با منبع گزارش های قابل جمع شدن مطابقت داشته باشد.
  • یک الگوریتم خاص برای جمع بندی و سطل سازی همه محرک ها در یک پنجره انتساب. این به محرک ها اجازه می دهد تا پارامتر value را مشخص کنند که برای یک مشخصات خاص خلاصه می شود ، اما به عنوان یک مقدار سطل گزارش شده است.

Triggers همچنین از اضافه کردن یک پارامتر مقدار اختیاری در فرهنگ لغت در event_trigger_data پشتیبانی می کند.

{
  "event_trigger_data": [
    {
      "trigger_data": "2",
      "value": 100,  // Defaults to 1
      "filters": ...
    },
    ...
  ]
}

هر ثبت نام ماشه با حداکثر یک ویژگی ماشه مطابقت دارد و مقدار خلاصه مرتبط با آن را به روز می کند. در سطح بالا ، در زمان ماشه ما:

  • فیلترهای انتساب جهانی را اعمال کنید.
  • برای هر مشخصات ماشه ، با استفاده از Spec's event_reporting_window event_trigger_data در مشخصات مشخص کنید. سطح بالا event_reporting_windows به عنوان یک مقدار پیش فرض عمل می کند در صورتی که هرگونه ویژگی ماشه از دست رفته event_report_windows Sub-Field باشد.
  • اولین مشخصات همسان برای انتساب انتخاب می شود و مقدار خلاصه با value افزایش می یابد.

هنگامی که event_report_window برای مشخصات مشخص شود ، ما مقدار خلاصه آن را به یک سطل ترسیم می کنیم و برای هر افزایش در سطل خلاصه ناشی از مقادیر ماشه نسبت داده شده ، گزارش سطح رویداد را ارسال می کنیم. گزارش ها با یک قسمت اضافی ، trigger_summary_bucket ارائه می شود.

{
  ...
  "trigger_summary_bucket": [<bucket start>, <bucket end>],
}

پیکربندی هایی که معادل نسخه فعلی هستند

موارد زیر به ترتیب تنظیمات معادل رویداد و منابع ناوبری APIS است. به خصوص برای منابع ناوبری ، این نشان می دهد که چرا سطح سر و صدا نسبت به منابع رویداد برای حفظ همان مقادیر اپسیلون بسیار زیاد است: منابع ناوبری فضای خروجی بسیار بیشتری دارند.

این امکان وجود دارد که با توجه به اینکه برخی از پارامترها می توانند به صورت پیش فرض یا هرس تنظیم شوند ، تنظیمات متعددی وجود داشته باشد.

منابع رویداد معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1],
    "event_report_windows": {
      "end_times": [<30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1],
  }],
  "max_event_level_reports": 1,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}
منابع ناوبری معادل
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3, 4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [<2 days>, <7 days>, <30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3],
  }],
  "max_event_level_reports": 3,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}

به عنوان مثال تنظیمات سفارشی

در زیر برخی از تنظیمات اضافی در خارج از پیش فرض وجود دارد. در تمام این مثالها ، معاملات توسعه دهنده شامل موارد زیر است:

  • کاهش ابعاد پیکربندی پیش فرض (#Triggers ، محرک داده های کاردینال ، #Windows) برای افزایش یک مورد دیگر برای حفظ سطح سر و صدا
  • کاهش برخی از ابعاد پیکربندی پیش فرض (#Triggers ، محرک داده های کاردینال ، #Windows) برای کاهش سطح سر و صدا

گزارش سطل های ارزش ماشه

این پیکربندی مثال از یک توسعه دهنده پشتیبانی می کند که می خواهد داده های ارزش را فقط برای یک پنجره گزارش دهی بهینه کند (به عنوان مثال 7 روز) ، و تجارت کمتری از ویندوز را برای سر و صدای کمتر معامله می کند. در این مثال ، هر ماشه ای که trigger_data به مقدار دیگری غیر از 0 تنظیم کند ، برای انتساب واجد شرایط نیست.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
    },
    "summary_window_operator": "value_sum",
    "summary_buckets": [5, 10, 100]
  }],
}

ماشه ها می توانند در مجموعه قسمت value ، که خلاصه و سطل می شوند ، ثبت شوند. به عنوان مثال اگر در طی 7 روز از ثبت نام منبع با مقادیر 1 ، 3 و 4 سه محرک وجود داشته باشد.

{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }

مقادیر خلاصه شده به 8 و در گزارش های زیر پس از 7 روز + 1 ساعت گزارش شده است:

// Report 1
{
  ...
  "trigger_summary_bucket": [5, 9]
}

در 7 روز بعد ، محرک های زیر ثبت شده اند:

{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }

مقادیر به 8 + 50 + 45 = 103 خلاصه می شوند. این گزارش های زیر را در 14 روز + 1 ساعت ارائه می دهد:

// Report 2
{
  ...
  "trigger_summary_bucket": [10, 99]
},

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
گزارش شمارش

این مثال نشان می دهد که چگونه یک توسعه دهنده می تواند یک منبع را پیکربندی کند تا تعداد محرک های حداکثر 10 را بدست آورد.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800] // 7 days represented in seconds
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }],
}

محرک های انتهایی با تنظیم trigger_data روی 0 شمارش شده و در 10 قرار می گیرند. مقدار ماشه از آنجا که summary_window_operator به حساب می آید نادیده گرفته می شود. اگر 4 محرک ثبت شده و به منبع نسبت داده شده باشد ، گزارش به این شکل خواهد بود:

// Report 1
{
  ...
  "trigger_summary_bucket": [1, 1]
}
// Report 2
{
  ...
  "trigger_summary_bucket": [2, 2]
}
// Report 3
{
  ...
  "trigger_summary_bucket": [3, 3]
}
// Report 4
{
  ...
  "trigger_summary_bucket": [4, 4]
}
باینری با گزارش مکرر

این پیکربندی مثال از یک توسعه دهنده پشتیبانی می کند که می خواهد یاد بگیرد که آیا حداقل یک تبدیل در 10 روز اول (صرف نظر از ارزش) رخ داده است ، اما می خواهد گزارش ها را در فواصل مکرر نسبت به پیش فرض دریافت کند. باز هم ، در این مثال هر ماشه ای که trigger_data به مقدار دیگری غیر از 0 تنظیم کند ، برای انتساب واجد شرایط نیست. به همین دلیل این مورد استفاده به عنوان باینری گفته می شود.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      // 1 day, 2 days, 3 days, 5 days, 7 days, 10 days represented in seconds
      "end_times": [86400, 172800, 259200, 432000, 604800, 864000]
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1]
  }],
}
مشخصات ماشه متفاوت از منبع به منبع دیگر
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}
{
  "trigger_specs": [
  {
    "trigger_data": [4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}

ما توسعه دهندگان را ترغیب می کنیم تا موارد استفاده متفاوتی را که ممکن است برای این پسوند API داشته باشند ، پیشنهاد کنند و این توضیح دهنده را با تنظیمات نمونه برای موارد استفاده به روز خواهیم کرد.

انتساب شبکه متقابل بدون تغییر مسیر

فناوری های تبلیغاتی باید از Redirects برای ثبت چندین محرک منبع انتساب و انجام انتساب شبکه متقابل استفاده کنند. این ویژگی به پشتیبانی از انتساب شبکه متقابل کمک می کند که در آن تغییر مسیر در شبکه ها امکان پذیر نیست. بیشتر بدانید .

فناوری های تبلیغاتی می توانند پیکربندی را در پاسخ ثبت نام ماشه بر اساس اینکه منابع ثبت شده توسط سایر فناوری های تبلیغاتی برای تولید منابع مشتق شده انتخاب شده اند ، ارسال کنند. این منابع مشتق شده سپس برای انتساب استفاده می شوند. اگر ماشه به یک منبع مشتق شده نسبت داده شود ، گزارش های کل تولید می شوند. تولید گزارش رویداد برای منابع مشتق شده پشتیبانی نمی شود.

تکنیک های تبلیغاتی می توانند از aggregation_keys در منابع ثبت شده خود که قصد دارند با فناوری های تبلیغاتی شریک به اشتراک بگذارند ، انتخاب کنند. این کلیدها را می توان در قسمت اختیاری shared_aggregation_keys ، واقع در زیر منبع ثبت نام منبع Attribution-Reporting-Register-Source اعلام کرد:

"shared_aggregation_keys": ["[key name1]", "[key name2]"]

منابع مشتق شده بر اساس پیکربندی تحت عنوان ثبت نام Attribution-Reporting-Register-Trigger تولید می شوند:

  // Specifies the configuration based on which derived sources should be
  // generated. Those derived sources will be included for source matching at the
  // time of attribution. For example, if adtech2 is registering a trigger with an
  // attribution_config with source_network as adtech1, available sources
  // registered by adtech1 will be considered with additional filtering criteria
  // applied to that set as mentioned in the attribution_config. Derived
  // sources can have different values to priority, post_install_exclusivity_window
  // etc.

  "attribution_config": [
    {
      // Derived sources are created from this adtech's registered sources
      "source_network": "[original source's adtech enrollment ID]",
      //(optional) Filter sources whose priority falls in this range
      "source_priority_range": {
        "start": [priority filter lower bound],
        "end": [priority filter upper bound]
      },
      // (optional) Filter sources whose at least one of filter maps matches these
      // filters
      "source_filters": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) Filter sources whose none of filter map matches these
      // filters
        "source_not_filters": {
          "key name 1": ["key1 value 1"]
        },
      // (optional) Apply this priority to the generated derived sources
      "priority": "[64 bit signed integer]",
      // (optional) The derived source will have expiry set as this or parent
      // source's, whichever is earlier
      "expiry": "[64 bit signed integer]",
      // (optional) set on the derived source
      "filter_data": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "[64-bit unsigned integer]"
    }
  ]

در اینجا یک نسخه با مقادیر مثال اضافه شده است:

  "attribution_config": [
    {
      "source_network": "adtech1-enrollment-id",
      "source_priority_range": {
        "start": 50,
        "end": 100
      },
      "source_filters": {
        "source_type": ["NAVIGATION"]
      },
      "source_not_filters": {
        "product_id": ["789"]
      },
      "priority": "30",
      "expiry": "78901",
      // (optional) set on the derived source
      "filter_data": {
        "product_id": ["1234"]
        },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "7890"
    }
  ]

دو قسمت اختیاری جدید برای ایجاد هدر ثبت نام اضافه می شود. این زمینه ها شناسه AD Tech برنده را در کلیدهای گزارش قابل جمع کردن فعال می کنند:

  • x_network_bit_mapping : شناسه ثبت نام به نقشه برداری بیت شناسه آگهی تبلیغاتی
  • x_network_data : افست (شیفت سمت چپ) برای برنده شدن در زمینه تبلیغات x_network_bit_mapping یا عملیات با قطعه کلید ماشه
مثال:
"Attribution-Reporting-Register-Trigger": {
  "attribution_config": [...],
  "aggregatable_trigger_data": [
    {
     "key_piece": "0x400",
     "source_keys": ["campaignCounts"]
      "x_network_data" : {
        "key_offset" : 12 // [64 bit unsigned integer]
      }
    }
    …
  ]
  …
  "x_network_bit_mapping": {
   // This mapping is used to generate trigger key pieces with AdTech identifier
   // bits. eg. If AdTechA's sources wins the attribution then 0x1 here will be
   // OR'd with the trigger key pieces to generate the final key piece.
    "AdTechA-enrollment_id": "0x1", // Identifier bits in hex for A
    "AdTechB-enrollment_id": "0x2"  // Identifier bits in hex for B
  }
  …
}

در اینجا محاسبه قطعه اصلی ماشه هنگام تولید گزارشی برای منبع ADTECHB ارائه شده است:

  • key_piece : 0x400 (010000000000)
  • key_offset : 12
  • ارزش enrollment_id Adtechb: 2 (010) (از x_network_bit_mapping )
  • قطعه کلید اصلی نتیجه: 0x400 | 0x2 << 12 = 0x2400

محدودیت ها

برای لیستی از قابلیت های در حال پیشرفت برای زمان اجرا SDK ، یادداشت های انتشار را مشاهده کنید.

اشکالات و مشکلات را گزارش کنید

بازخورد شما بخش مهمی از ماسهبازی حریم خصوصی در Android است! به ما اطلاع دهید و از هرگونه مسائلی که می یابید یا ایده هایی را برای بهبود ماسهبازی حریم خصوصی در اندروید به ما اطلاع دهید.

،
پیش

همانطور که از طریق Sandbox حریم خصوصی در مستندات Android خوانده اید ، از دکمه پیش نمایش توسعه دهنده یا Beta برای انتخاب نسخه برنامه ای که با آنها کار می کنید استفاده کنید ، زیرا ممکن است دستورالعمل ها متفاوت باشد.


ارائه بازخورد

API گزارشگر Attribution به گونه ای طراحی شده است که با از بین بردن اعتماد به شناسه های کاربر متقابل ، و پشتیبانی از موارد استفاده کلیدی برای اندازه گیری و اندازه گیری تبدیل در برنامه ها ، حریم شخصی بهبود یافته را فراهم می کند. این راهنمای توسعه دهنده نحوه پیکربندی و آزمایش API های گزارش انتساب را برای ثبت کلیک ها ، نماها و تبدیل های تبلیغاتی با استفاده از روش هایی که باعث ثبت محرک ها و منابع مربوطه برای چنین رویدادهایی می شود ، توصیف می کند.

این راهنما به شما می آموزد که چگونه می توانید نقاط پایانی سرور را تنظیم کنید و یک برنامه مشتری ایجاد کنید که این سرویس ها را فراخوانی می کند. در مورد طراحی کلی API گزارشگر API در پیشنهاد طراحی بیشتر بدانید.

شرایط کلیدی

  • منابع انتساب به کلیک یا نماها مراجعه می کنند.
  • محرک ها رویدادهایی هستند که می توانند به تبدیل ها نسبت داده شوند.
  • گزارش ها حاوی داده هایی در مورد یک ماشه و منبع انتساب مربوطه است. این گزارش ها در پاسخ به وقایع ماشه ارسال می شوند. API گزارش دهنده انتساب از گزارش های سطح رویداد و گزارش های قابل جمع پشتیبانی می کند.

قبل از اینکه شروع کنی

برای استفاده از API گزارش انتساب ، وظایف سمت سرور و سمت مشتری را که در بخش های بعدی ذکر شده است ، انجام دهید.

تنظیم نقاط پایانی API گزارش انتساب را تنظیم کنید

API گزارشگر Attribution به مجموعه ای از نقاط پایانی نیاز دارد که می توانید از یک دستگاه تست یا شبیه ساز به آن دسترسی پیدا کنید. برای هر یک از کارهای سمت زیر سرور یک نقطه پایانی ایجاد کنید:

چندین روش برای تنظیم نقاط پایانی مورد نیاز وجود دارد:

  • سریعترین راه برای برخاستن و اجرای آن ، استقرار تعاریف سرویس OpenAPI V3 از مخزن کد نمونه ما به یک بستر مسخره یا میکروسرویس است. می توانید از Postman ، Prism یا هر سیستم عامل سرور مسخره دیگری که این قالب را می پذیرد استفاده کنید. هر نقطه پایانی را مستقر کنید و URI ها را برای استفاده در برنامه خود پیگیری کنید. برای تأیید تحویل گزارش ، به تماس هایی که قبلاً به پلت فرم Mock یا Serverless انجام شده است مراجعه کنید.
  • سرور مستقل خود را با استفاده از نمونه Kotlin مبتنی بر بوت بهار اجرا کنید. این سرور را در ارائه دهنده ابر یا زیرساخت های داخلی خود مستقر کنید.
  • برای ادغام نقاط پایانی در سیستم موجود خود از تعاریف سرویس به عنوان نمونه استفاده کنید.

ثبت نام منبع را بپذیرید

این نقطه پایانی باید از URI مشابه موارد زیر قابل دسترسی باشد:

https://adtech.example/attribution_source

هنگامی که یک برنامه مشتری یک منبع انتساب را ثبت می کند ، URI را برای این نقطه پایانی سرور فراهم می کند. سپس API گزارش انتساب درخواست می کند و یکی از هدرهای زیر را شامل می شود:

  • برای رویدادهای کلیک:

    Attribution-Reporting-Source-Info: navigation
    
  • برای مشاهده رویدادها:

    Attribution-Reporting-Source-Info: event
    

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهید:

// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  // Attribution source metadata specifying histogram contributions in aggregate
  // report.
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  },

    "debug_key": "[64-bit unsigned integer]",
    "debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا مثالی با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Source: {
  "destination": "android-app://com.example.advertiser",
  "source_event_id": "234",
  "expiry": "259200",
  "event_report_window": "172800",
  "aggregatable_report_window": "172800",
  "priority": "5",
  "filter_data": {
    "product_id": ["1234"]
  },
  "aggregation_keys": {
  // Generates a "0x159" key piece named (low order bits of the key) for the key
  // named "campaignCounts".
  // User saw an ad from campaign 345 (out of 511).
    "campaignCounts": "0x159",

  // Generates a "0x5" key piece (low order bits of the key) for the key named
  // "geoValue".
  // Source-side geo region = 5 (US), out of a possible ~100 regions.
    "geoValue": "0x5",
  },
  // Opts in to receiving verbose debug reports
  "debug_reporting": true
}

Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890

اگر Attribution-Reporting-Redirects حاوی URI شرکای فناوری تبلیغاتی باشد ، API گزارشگر انتساب سپس درخواست مشابهی را برای هر URI ایجاد می کند. هر شریک AD Tech باید سرور را پیکربندی کند که با این هدرها پاسخ دهد:

Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "web_destination": "[eTLD+1]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "event_report_window": "[64-bit signed integer]",
  "aggregatable_report_window": "[64-bit signed integer]",
  "priority": "[64 bit signed integer]",
  "filter_data": {
    "[key name 1]": ["key1 value 1", "key1 value 2"],
    "[key name 2]": ["key2 value 1", "key2 value 2"],
    // Note: "source_type" key will be automatically generated as
    // one of {"navigation", "event"}.
  },
  "aggregation_keys": {
    "[key1 name]": "[key1 value]",
    "[key2 name]": "[key2 value]",
  }
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

ثبت نام ماشه تبدیل را بپذیرید

این نقطه پایانی باید از URI مشابه موارد زیر قابل دسترسی باشد:

https://adtech.example/attribution_trigger

هنگامی که یک برنامه مشتری یک رویداد ماشه را ثبت می کند ، URI را برای این نقطه پایانی سرور فراهم می کند. سپس API گزارش انتساب درخواست می کند و یکی از هدرهای زیر را شامل می شود:

نقطه پایانی سرور خود را پیکربندی کنید تا با موارد زیر پاسخ دهید:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data returned" in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // "filter" and "not_filters" are optional fields which allow configuring
    // event trigger data based on source's filter_data. They consist of a
    // filter set, which is a list of filter maps. An event_trigger_data object
    // is ignored if none of the filter maps in the set match the source's
    // filter data.
    // Note: "source_type" can be used as a key in a filter map to filter based
    // on the source's "navigation" or "event" type. The first
    // Event-Trigger that matches (based on the filters/not_filters) will be
    // used for report generation. If none of the event-triggers match, no
    // event report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it won't be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it won't
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  // Specify a list of dictionaries that generates aggregation keys.
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]]
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16]
  // to contribute to each key that is attached to aggregation keys in the
  // order they are generated.
  "aggregatable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the
     // aggregate histogram.
    {
     "[key_name]": [value]
    },
    ..
  ],
  aggregatable_deduplication_keys: [{
  deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_H]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
  },
  ...
  {
  "deduplication_key": [unsigned 64-bit integer],
    "filters": {
        "category": [filter_1, …, filter_D]
      },
    "not_filters": {
        "category": [filter_1, …, filter_J]
      }
    }
  ]

  "debug_key": "[64-bit unsigned integer]",
  "debug_reporting": [boolean]

}
// Specify additional ad tech URLs to register this trigger with.
// Repeated Header field "Attribution-Reporting-Redirect"
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>

در اینجا مثالی با مقادیر نمونه اضافه شده است:

Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    "trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["event"]
    }]
  },
  {
    "trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
    "priority": "3",
    "deduplication_key": "3344"
    "filters": [{ // Filter strings can not exceed 25 characters
      "product_id": ["1234"],
      "source_type": ["navigation"]
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary independently adds pieces to multiple source keys.
    {
      // Conversion type purchase = 2 at a 9-bit offset, i.e. 2 << 9.
      // A 9-bit offset is needed because there are 511 possible campaigns,
      // which takes up 9 bits in the resulting key.
      "key_piece": "0x400",// Conversion type purchase = 2
      // Apply this key piece to:
      "source_keys": ["campaignCounts"]
       // Filter strings can not exceed 25 characters
    },
    {
      // Purchase category shirts = 21 at a 7-bit offset, i.e. 21 << 7.
      // A 7-bit offset is needed because there are ~100 regions for the geo
      // key, which takes up 7 bits of space in the resulting key.
      "key_piece": "0xA80",
      // Apply this key piece to:
      "source_keys": ["geoValue", "nonMatchingIdsAreIgnored"]
      // source_key values must not exceed the limit of 25 characters
    }
  ],
  "aggregatable_values":
    {
      // Privacy budget for each key is L1 / 2 = 2^15 (32768).
      // Conversion count was 1.
      // Scale the count to use the full budget allocated: 1 * 32768 = 32768.
      "campaignCounts": 32768,

      // Purchase price was $52.
      // Purchase values for the app range from $1 to $1,024 (integers only).
      // Scaling factor applied is 32768 / 1024 = 32.
      // For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
      "geoValue": 1664
    }
  ,
  // aggregatable_deduplication_keys is an optional field. Up to 50 "keys"
  // can be included in the aggregatable_deduplication_keys list. Filters, not
  // filters, and deduplication_key are optional fields. If deduplication_key
  // is omitted, it will be treated as a null value. See
  // https://wicg.github.io/attribution-reporting-api/#triggering-aggregatable-attribution
  aggregatable_deduplication_keys:
  [
    {
    deduplication_key": 3,
        "filters": {
          "category": [A]
        }
    },
    {
    "deduplication_key": 4,
        "filters": {
          "category": [C, D]
        },
        "not_filters": {
          "category": [F]
        }
    }
  ]
  // Opts into receiving verbose debug reports
  "debug_reporting": true
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567

در هر شناسه کلید و رشته فیلتر محدود 25 بایت وجود دارد. این بدان معنی است که شناسه های کلیدی جمع آوری و رشته های فیلتر شما نباید از 25 کاراکتر تجاوز کنند. در این مثال ، campaignCounts 14 کاراکتر است ، بنابراین یک شناسه کلید جمع آوری معتبر است و 1234 4 نویسه است ، بنابراین یک رشته فیلتر معتبر است. اگر یک شناسه کلید جمع آوری یا رشته فیلتر از 25 کاراکتر فراتر رود ، ماشه نادیده گرفته می شود.

اگر Attribution-Reporting-Redirect حاوی URI از شرکای فناوری تبلیغاتی باشد ، API گزارش انتساب سپس درخواست مشابهی را برای هر URI ایجاد می کند. هر شریک AD Tech باید سرور را پیکربندی کند که با این هدرها پاسخ دهد:

// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
  "event_trigger_data": [{
    // "trigger_data" returned in event reports is truncated to
    // the last 1 or 3 bits, based on conversion type.
    "trigger_data": "[unsigned 64-bit integer]",
    "priority": "[signed 64-bit integer]",
    "deduplication_key": "[signed 64-bit integer]",
    // filter and not_filters are optional fields which allow configuring
    // different event trigger data based on source's filter_data. They
    // consist of a filter set, which is a list of filter maps. An
    // event_trigger_data object is ignored if none of the filter maps in the
    // set match the source's filter data. Note: "source_type" can be used as
    // a key in a filter map to filter based on the source's "navigation" or
    // "event" type. The first Event-Trigger that matches (based on the
    // filters/not_filters) will be used for report generation. If none of the
    // event-triggers match, no report will be generated.
    "filters": [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from filters or source's filter_data, it will not be
      // used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }],
    "not_filters":  [{
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from not_filters or source's filter_data, it will not
      // be used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }]
  }],
  "aggregatable_trigger_data": [
    // Each dictionary entry independently adds pieces to multiple source keys.
    {
      "key_piece": "[key piece value]",
      "source_keys": ["[key name the key piece value applies to]",
      ["list of IDs in source to match. Non-matching IDs are ignored"]],
      // filters/not_filters are optional fields similar to event trigger data
      // filter fields.
      "filters": [{
        "[key name 1]": ["key1 value 1", "key1 value 2"]
      }],
      "not_filters":  [{
          "[key name 1]": ["key1 value 1", "key1 value 2"],
          "[key name 2]": ["key2 value 1", "key2 value 2"],
      }]
    },
    ..
  ],
  // Specify an amount of an abstract value which can be integers in [1, 2^16] to
  // contribute to each key that is attached to aggregation keys in the order they
  // are generated.
  "aggregatable_values": [
    // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
    // histogram.
    {
     "[key_name]": [value]
    }
  ]
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.

گزارش های سطح رویداد را بپذیرید

این نقطه پایانی باید از URI قابل پرداخت باشد. برای کسب اطلاعات بیشتر در مورد ثبت نام URIS ، به ثبت نام در حساب Sandbox حریم خصوصی مراجعه کنید. . _

https://adtech.example/.well-known/attribution-reporting/report-event-attribution

این سرور را پیکربندی کنید تا درخواست های JSON را که از قالب زیر استفاده می کنند ، بپذیرید:

{
  "attribution_destination": "android-app://com.advertiser.example",
  "source_event_id": "12345678",
  "trigger_data": "2",
  "report_id": "12324323",
  "source_type": "navigation",
  "randomized_trigger_rate": "0.02"
   [Optional] "source_debug_key": "[64-bit unsigned integer]",
   [Optional] "trigger_debug_key": "[64-bit unsigned integer]",
}

کلیدهای اشکال زدایی امکان بینش اضافی در مورد گزارش های انتساب شما را فراهم می کند. در مورد پیکربندی آنها بیشتر بدانید .

گزارش های قابل جمع را بپذیرید

این نقطه پایانی باید از URI قابل پرداخت باشد. برای کسب اطلاعات بیشتر در مورد ثبت نام URIS ، به ثبت نام در حساب Sandbox حریم خصوصی مراجعه کنید. . _

https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution

هر دو زمینه رمزگذاری شده و بدون رمزگذاری برای گزارش های قابل جمع شدن جمع می شوند. گزارش های رمزگذاری شده شما را قادر می سازد تا با سرویس جمع آوری آزمایش را شروع کنید ، در حالی که زمینه رمزگذاری نشده بینشی را در مورد نحوه تنظیم جفت های ارزش کلید در حال ساخت داده ها فراهم می کند.

این سرور را پیکربندی کنید تا درخواست های JSON را که از قالب زیر استفاده می کنند ، بپذیرید:

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform does not yet encrypt aggregate reports.
  // Currently, the "debug_cleartext_payload" field holds unencrypted reports.
  "aggregation_service_payloads": [
    {
      "payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
      "key_id": "[string identifying public key used to encrypt payload]",

      "debug_cleartext_payload": "[unencrypted payload]"
    },
  ],

  "source_debug_key": "[64 bit unsigned integer]",
  "trigger_debug_key": "[64 bit unsigned integer]"
}

کلیدهای اشکال زدایی امکان بینش اضافی در مورد گزارش های انتساب شما را فراهم می کند. در مورد پیکربندی آنها بیشتر بدانید .

مشتری Android را تنظیم کنید

برنامه مشتری منابع انتساب و محرک را ثبت می کند و تولید گزارش سطح و قابل جمع شدن را امکان پذیر می کند. برای تهیه یک دستگاه یا شبیه ساز مشتری Android برای استفاده از API گزارش انتساب ، موارد زیر را انجام دهید:

  1. محیط توسعه خود را برای ماسهبازی حریم خصوصی در Android تنظیم کنید .
  2. یک تصویر سیستم را روی یک دستگاه پشتیبانی شده نصب کنید یا یک شبیه ساز را تنظیم کنید که شامل پشتیبانی از جعبه ماسه حریم خصوصی در Android باشد.
  3. با اجرای دستور ADB زیر ، دسترسی به API گزارش انتساب را فعال کنید . (API به طور پیش فرض غیرفعال است.)

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
    
  4. اگر به صورت محلی در حال آزمایش API گزارش انتساب (مانند آزمایش بر روی دستگاهی هستید که به جسمی دسترسی دارید) ، این دستور را برای غیرفعال کردن ثبت نام اجرا کنید:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
    
  5. مجوز ACCESS_ADSERVICES_ATTRIBUTION را در پرونده مانیفست Android خود قرار دهید و یک پیکربندی خدمات تبلیغاتی را برای برنامه خود ایجاد کنید تا از API های گزارشگری Attribution استفاده کنید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (اختیاری) اگر قصد دریافت گزارش های اشکال زدایی را دارید ، مجوز ACCESS_ADSERVICES_AD_ID را در پرونده مانیفست اندرویدی خود قرار دهید:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. پیکربندی خدمات تبلیغاتی را در عنصر <application> مانیفست خود ارجاع دهید:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. خدمات AD Services XML را که در مانیفست ارجاع شده است ، مانند res/xml/ad_services_config.xml مشخص کنید. در مورد مجوزهای خدمات تبلیغاتی و کنترل دسترسی SDK بیشتر بدانید.

    <ad-services-config>
        <attribution allowAllToAccess="true" />
    </ad-services-config>
    

ثبت رویدادهای تبلیغاتی

برنامه شما باید منابع و تبدیل ها را به عنوان اتفاق بیفتد تا اطمینان حاصل شود که به درستی گزارش شده است. کلاس MeasurementManager روش هایی را برای کمک به شما در ثبت وقایع منبع انتساب و محرک های تبدیل به شما کمک می کند.

یک رویداد منبع انتساب را ثبت کنید

هنگامی که یک آگهی مشاهده یا کلیک می شود ، یک برنامه ناشر برای ثبت نام منبع انتساب همانطور که در قطعه کد نشان داده شده است ، با ثبت registerSource() تماس می گیرد.

API گزارش انتساب از انواع زیر از رویدادهای منبع انتساب پشتیبانی می کند:

  • کلیک ، که شما به طور معمول در یک روش پاسخ به تماس مشابه با onClick() ثبت می کنید. رویداد ماشه مربوطه معمولاً به زودی پس از رویداد کلیک اتفاق می افتد. این نوع رویداد اطلاعات بیشتری در مورد تعامل کاربر ارائه می دهد و بنابراین نوع خوبی از منبع انتساب برای اولویت بالایی است.
  • بازدیدها ، که شما به طور معمول در یک روش پاسخ به تماس مشابه با onAdShown() ثبت می کنید. رویداد ماشه مربوطه ممکن است ساعات یا چند روز پس از رویداد مشاهده رخ دهد.

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
  Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
    exampleClickEvent = event
    true
}

// Register Click Event
measurementManager.registerSource(
        attributionSourceUri,
        exampleClickEvent,
        CALLBACK_EXECUTOR,
        future::complete)

// Register View Event
measurementManager.registerSource(
        attributionSourceUri,
        null,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts attribution source
// registration.
Uri attributionSourceUri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event)) -> {
    exampleClickEvent = event;
    return true;
}

// Register Click Event
measurementManager.registerSource(attributionSourceUri, exampleClickEvent,
        CALLBACK_EXECUTOR, future::complete);

// Register View Event
measurementManager.registerSource(attributionSourceUri, null,
        CALLBACK_EXECUTOR, future::complete);

پس از ثبت نام ، API درخواست HTTP Post را به نقطه پایانی سرویس در آدرس مشخص شده توسط attributionSourceUri صادر می کند. پاسخ نقطه پایانی شامل مقادیر destination, source_event_id, expiry و source_priority است.

اگر فناوری تبلیغاتی مبداء بخواهد ثبت نام های منبع را به اشتراک بگذارد ، منبع اصلی انتساب URI می تواند شامل تغییر مسیر به سایر نقاط پایانی فناوری باشد. محدودیت ها و قوانینی که در مورد تغییر مسیر اعمال می شود ، در پیشنهاد فنی به تفصیل شرح داده شده است.

پشتیبانی برای تغییر مسیر زنجیره دیزی برای registerSource و registerTrigger اضافه شده است. علاوه بر عنوان ثبت نام ، مصرف کننده API هم اکنون می تواند HTTP را به عنوان پاسخ سرور که شامل یک کد وضعیت 302 و یک هدر "مکان" با URL بعدی برای بازدید برای ثبت نام اضافی است ، ارائه دهد.

فقط قسمت "مقصد" ارائه شده در اولین بازدید در سراسر زنجیره دیزی استفاده می شود. تعداد بازدیدها همان حد را با عنوان های "انتساب-گزارشگر-REDIRECT" دارد. این پشتیبانی تغییر مسیر علاوه بر پشتیبانی موجود "انتساب-گزارشگر-REDIRECT" موجود است و اگر هر دو وجود داشته باشند ، "انتساب-گزارشگر-REDIRECT" اولویت می گیرد.

یک رویداد ماشه تبدیل را ثبت کنید

To register a conversion trigger event, call registerTrigger() in your app:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
    Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")

val future = CompletableFuture<Void>()

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URI of the server-side endpoint that accepts trigger registration.
Uri attributionTriggerUri =
        Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA");

CompletableFuture<Void> future = new CompletableFuture<>();

// Register trigger (conversion)
measurementManager.registerTrigger(
        attributionTriggerUri,
        CALLBACK_EXECUTOR,
        future::complete)

After registration, the API issues an HTTP POST request to the service endpoint at the address specified by attributionTriggerUri . The endpoint's response includes values for event and aggregate reports.

If the originating ad tech platform allows trigger registrations to be shared, the URI can include redirects to URIs that belong to other ad tech platforms. The limits and rules applicable to the redirects are detailed in the technical proposal .

Register cross app and web measurement

In the case where both an app and browser play a part in the user's journey from source to trigger, there are subtle differences in the implementation of registering ad events. If a user sees an ad on an app and is redirected to a browser for a conversion, the source is registered by the app, and the conversion by the web browser. Similarly, if a user starts on a web browser and is directed to an app for conversion, the browser registers the source, and the app registers the conversion.

Since there are differences in the way ad techs are organized on the web and on Android, we have added new APIs to register sources and triggers when they take place on browsers. The key difference between these APIs and the corresponding app-based APIs is that we expect the browser to follow the redirects, apply any browser-specific filters, and pass on the valid registrations to the platform by calling registerWebSource() or registerWebTrigger() .

The following code snippet shows an example of the API call that the browser makes to register an attribution source before directing the user to an app:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager =
        context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
val sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build()

val sourceParams = Arrays.asList(sourceParam1, sourceParam2, sourceParam3)
val publisherOrigin = Uri.parse("https://publisher.example")
val appDestination = Uri.parse("android-app://com.example.store")
val webDestination = Uri.parse("https://example.com")

val future = CompletableFuture<Void>()

adView.setOnTouchListener {_: View?, event: MotionEvent? ->
    exampleClickEvent = event
    true
}
val clickRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(event)
      .build()
val viewRegistrationRequest = WebSourceRegistrationRequest.Builder(
          sourceParams,
          publisherOrigin)
      .setAppDestination(appDestination)
      .setWebDestination(webDestination)
      .setInputEvent(null)
      .build()

// Register a web source for a click event.
measurementManager.registerWebSource(
        clickRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

// Register a web source for a view event.
measurementManager.registerWebSource(
        viewRegistrationRequest,
        CALLBACK_EXECUTOR,
        future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept attribution source
// registration.
WebSourceParams sourceParam1 = WebSourceParams.Builder(Uri.parse(
        "https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebSourceParams sourceParam2 = WebSourceParams.Builder(Uri.parse(
        "https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

WebSourceParams sourceParam3 = WebSourceParams.Builder(Uri.parse(
        "https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
    .build();

List<WebSourceParams> sourceParams =
        Arrays.asList(sourceParam1, sourceParam2, sourceParam3);
Uri publisherOrigin = Uri.parse("https://publisher.example");
Uri appDestination = Uri.parse("android-app://com.example.store");
Uri webDestination = Uri.parse("https://example.com");

CompletableFuture<Void> future = new CompletableFuture<>();

adView.setOnTouchListener(v, event) -> {
    exampleClickEvent = event;
    return true;
}

WebSourceRegistrationRequest clickRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(event)
    .build();
WebSourceRegistrationRequest viewRegistrationRequest =
        new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
    .setAppDestination(appDestination)
    .setWebDestination(webDestination)
    .setInputEvent(null)
    .build();

// Register a web source for a click event.
measurementManager.registerWebSource(clickRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

// Register a web source for a view event.
measurementManager.registerWebSource(viewRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

The following code snippet shows an example of the API call that the browser makes to register a conversion after the user has been directed from the app:

کاتلین

companion object {
    private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}

val measurementManager = context.getSystemService(MeasurementManager::class.java)

// Use the URIs of the server-side endpoints that accept trigger registration.
val triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build()

val triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build()

val triggerParams = Arrays.asList(triggerParam1, triggerParam2)
val advertiserOrigin = Uri.parse("https://advertiser.example")

val future = CompletableFuture<Void>()

val triggerRegistrationRequest = WebTriggerRegistrationRequest.Builder(
        triggerParams,
        advertiserOrigin)
    .build()

// Register the web trigger (conversion).
measurementManager.registerWebTrigger(
    triggerRegistrationRequest,
    CALLBACK_EXECUTOR,
    future::complete)

جاوا

private static final Executor CALLBACK_EXECUTOR =
        Executors.newCachedThreadPool();

MeasurementManager measurementManager =
        context.getSystemService(MeasurementManager.class);

// Use the URIs of the server-side endpoints that accept trigger registration.
WebTriggerParams triggerParam1 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
    // True, if debugging is allowed for the ad tech.
    .setDebugKeyAllowed(true)
    .build();

WebTriggerParams triggerParam2 = WebTriggerParams.Builder(Uri.parse(
        "https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
    .setDebugKeyAllowed(false)
    .build();

List<WebTriggerParams> triggerParams =
        Arrays.asList(triggerParam1, triggerParam2);
Uri advertiserOrigin = Uri.parse("https://advertiser.example");

CompletableFuture<Void> future = new CompletableFuture<>();

WebTriggerRegistrationRequest triggerRegistrationRequest =
        new WebTriggerRegistrationRequest.Builder(
            triggerParams, advertiserOrigin)
    .build();

// Register the web trigger (conversion).
measurementManager.registerWebTrigger( triggerRegistrationRequest,
        CALLBACK_EXECUTOR, future::complete);

Adding noising for privacy

Event-level reports contain destination, attribution source ID and trigger data. They are sent in the original (unencrypted) format to the reporting origin. To protect user's privacy, noise can be added to make it more difficult to identify an individual user. Noised event-level reports are generated and sent in accordance with the differential-privacy framework. These are the default noise percentage values for different scenarios:

نوع منبع

Source destination value

Noised report probability per source registration

چشم انداز

Either app or web

0.0000025

چشم انداز

App and web

0.0000042

کلیک

Either app or web

0.0024263

کلیک

App and web

0.0170218

In app-to-web attribution measurement, where sources can drive conversion to both app and web destinations, event-level reports can specify whether the trigger occurred on app or web. To compensate for this additional detail, the noised reports generated are up to ~7x for clicks and ~1.7x for views.

Some ad techs don't require event-level reports to specify whether the trigger occurred on either the app or web destination. Ad techs can use the coarse_event_report_destinations field under the Attribution-Reporting-Register-Source header to reduce noise. If a source with the coarse_event_report_destinations field specified wins attribution, the resulting report includes both app and web destinations without distinction as to where the actual trigger occurred.

In the following examples, a user clicks on an ad, and that source is registered with the API. The user then converts on both the advertiser app and the advertiser's website. Both of these conversions are registered as triggers and attributed to the initial click.

A click-based source registration HTTP header:

Attribution-Reporting-Register-Source: {
    "destination": "android-app://com.advertiser.example",
    "web_destination": "https://advertiser.com",
    "source_event_id": "234",
    "expiry": "60000",
    "priority": "5",
    // Ad tech opts out of receiving app-web destination distinction
    // in event report, avoids additional noise
    "coarse_event_report_destinations": "true"
}

A trigger is registered from the app with the package name com.advertiser.example :

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "1",
    "priority": "1"
    }],
}

A trigger is registered from a browser from the website with the eTLD+1 domain https://advertiser.com :

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "2",
    "priority": "2"
    }],
}

The resulting event-level reports are generated. Assuming both triggers get attributed to the source, the following event-level reports are generated:

  {
    "attribution_destination": ["android-app://com.advertiser.example,https://advertiser.com"],
    "scheduled_report_time": "800176400",
    "source_event_id": "53234",
    "trigger_data": "1",
    // Can be "event" if source were registered by user viewing the ad
    "source_type": "navigation",
    // Would be 0.0170218 without coarse_event_report_destinations as true in the source
    "randomized_trigger_rate": 0.0024263
  }

Generate and deliver reports

The Attribution Reporting API sends reports to the endpoints on your server that accept event-level reports and aggregatable reports .

Force reporting jobs to run

After you register an attribution source event or register a trigger event, the system schedules the reporting job to run. By default, this job runs every 4 hours. For testing purposes, you can force the reporting jobs to run or shorten the intervals between jobs.

Force attribution job to run:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 5

Force event-level reporting job to run:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 3

Force aggregatable reporting job to run:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 7

Check the output in logcat to see when the jobs have run. It should look something like the following:

JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true

Force delivery of reports

Even if the reporting job is forced to run, the system still sends out reports according to their scheduled delivery times , which range from a couple of hours to several days. For testing purposes, you can advance the device system time to be after the scheduled delays to initiate the report delivery.

Verify reports on your server

Once reports are sent, verify delivery by checking received reports, applicable server logs such as the mock server history or your custom system.

Decode your aggregate report

When receiving an aggregate report, the debug_cleartext_payload field holds an unencrypted version of your aggregate report. While this version of your report is unencrypted, it still needs to be decoded.

Below is an example of decoding the contents of the debug_cleartext_payload field in two steps: the first using Base 64 decoding, and the second using CBOR decoding.

String base64DebugPayload  = "omRkYXRhgqJldmFsdWVEAAAGgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAKhaJldmFsdWVEAACAAGZidWNrZXRQAAAAAAAAAAAAAAAAAAAFWWlvcGVyYXRpb25paGlzdG9ncmFt";
byte[] cborEncoded = Base64.getDecoder().decode(base64DebugPayload);

// CbodDecoder comes from this library https://github.com/c-rack/cbor-java
final List<DataItem> dataItems = new CborDecoder(new ByteArrayInputStream(cborEncoded)).decode();

// In here you can see the contents, but the value will be something like:
// Data items: [{ data: [{ value: co.nstant.in.cbor.model.ByteString@a8b5c07a,
//   bucket: co.nstant.in.cbor.model.ByteString@f812097d },
//   { value: co.nstant.in.cbor.model.ByteString@a8b5dfc0,
//   bucket: co.nstant.in.cbor.model.ByteString@f8120934 }], operation: histogram }]
Log.d("Data items : " + dataItems);

// In order to see the value for bucket and value, you can traverse the data
// and get their values, something like this:
final Map payload = (Map) dataItems.get(0);
final Array payloadArray = (Array) payload.get(new UnicodeString("data"));

payloadArray.getDataItems().forEach(i -> {
    BigInteger value = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("value"))).getBytes());
    BigInteger bucket = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("bucket"))).getBytes());
    Log.d("value : " + value + " ;bucket : " + bucket);
});

آزمایش کردن

To help you get started with the Attribution Reporting API, you can use the MeasurementSampleApp project on GitHub. This sample app demonstrates attribution source registration and trigger registration.

For server endpoints, consider the following reference resources or your custom solution:

  • MeasurementAdTechServerSpec includes OpenAPI service definitions, which can be deployed to a supported mock or microservices platforms.
  • MeasurementAdTechServer includes a reference implementation of a mock server based on Spring Boot app for Google App Engine.

پیش نیازها

Deploy mock APIs on remote endpoints accessible from your test device or emulator. For ease of testing, refer to the MeasurementAdTechServerSpec and MeasurementAdTechServer sample projects.

Functionality to test

  • Exercise attribution source and conversion trigger registrations. Check that server-side endpoints respond with the correct format.
  • Execute reporting jobs .
  • Verify delivery of reports on your test server's backend or console.

ویژگی های آینده

Flexible event-level configuration

The default configuration for event level reporting is advised for starting utility testing, but may not be ideal for all use cases. The Attribution Reporting API will support optional, more flexible configurations so that ad techs have increased control over the structure of their event level reports and are able to maximize the utility of the data. This additional flexibility will be introduced into the Attribution Reporting API in two phases:

  • Phase 1 : Lite flexible event level configuration; a subset of Phase 2.
  • Phase 2 : Full version of flexible event level configuration.

Phase 1: Lite flexible event level

We will add the following two optional parameters to the JSON in Attribution-Reporting-Register-Source :

  • max_event_level_reports
  • event_report_windows
{
  ...
  // Optional. This is a parameter that acts across all trigger types for the
  // lifetime of this source. It restricts the total number of event-level
  // reports that this source can generate. After this maximum is hit, the
  // source is no longer capable of producing any new data. The use of
  // priority in the trigger attribution algorithm in the case of multiple
  // attributable triggers remains unchanged. Defaults to 3 for navigation
  // sources and 1 for event sources
  "max_event_level_reports": <int>,

  // Optional. Represents a series of time windows, starting at 0. Reports
  // for this source will be delivered an hour after the end of each window.
  // Time is encoded as seconds after source registration. If
  // event_report_windows is omitted, will use the default windows. This
  // field is mutually exclusive with the existing `event_report_window` field.
  // // End time is exclusive.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

Custom configuration example

This example configuration supports a developer who wants to optimize for receiving reports at earlier reporting windows.

{
  ...
  "max_event_level_reports": 2,
  "event_report_windows": {
    "end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
  }
}

Phase 2: Full flexible event level

In addition to the parameters that were added in Phase 1, we will add an additional optional parameter trigger_specs to the JSON in Attribution-Reporting-Register-Source .

{
  // A trigger spec is a set of matching criteria, along with a scheme to
  // generate bucketized output based on accumulated values across multiple
  // triggers within the specified event_report_window. There will be a limit on
  // the number of specs possible to define for a source.
  "trigger_specs": [{
    // This spec will only apply to registrations that set one of the given
    // trigger data values (non-negative integers) in the list.
    // trigger_data will still appear in the event-level report.
    "trigger_data": [<int>, ...]

    // Represents a series of time windows, starting at the source registration
    // time. Reports for this spec will be delivered an hour after the end of
    // each window. Time is encoded as seconds after source registration.
    // end_times must consist of strictly increasing positive integers.
    //
    // Note: specs with identical trigger_data cannot have overlapping windows;
    // this ensures that triggers match at most one spec. If
    // event_report_windows is omitted, will use the "event_report_window" or
    // "event_report_windows" field specified at the global level for the source
    // (or the default windows if none are specified). End time is exclusive.
    "event_report_windows": {
      "start_time": <int>,
      "end_times": [<int>, ...],
    }

    // Represents an operator that summarizes the triggers within a window
    // count: number of triggers attributed within a window
    // value_sum: sum of the value of triggers within a window
    // The summary is reported as an index into a bucketization scheme. Defaults
    // to "count"
    "summary_window_operator": <one of "count" or "value_sum">,

    // Represents a bucketization of the integers from [0, MAX_INT], encoded as
    // a list of integers where new buckets begin (excluding 0 which is
    // implicitly included).
    // It must consist of strictly increasing positive integers.
    //
    // e.g. [5, 10, 100] encodes the following ranges:
    // [[0, 4], [5, 9], [10, 99], [100, MAX_INT]]
    //
    // At the end of each reporting window, triggers will be summarized into an
    // integer which slots into one of these ranges. Reports will be sent for
    // every new range boundary that is crossed. Reports will never be sent for
    // the range that includes 0, as every source is initialized in this range.
    //
    // If omitted, then represents a trivial mapping
    // [1, 2, ... , MAX_INT]
    // With MAX_INT being the maximum int value defined by the browser.
    "summary_buckets": [<bucket start>, ...]
  }, {
    // Next trigger_spec
  } ...],

  // See description in phase 1.
  "max_event_level_reports": <int>
  // See description in phase 1.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

This configuration fully specifies the output space of the event-level reports, per source registration. For every trigger spec, we fully specify:

  • A set of matching criteria:
    • Which specific trigger data this spec applies to. This source is eligible to be matched only with triggers that have one of the specified trigger_data values in the trigger_specs . In other words, if the trigger would have matched this source but its trigger_data is not one of the values in the source's configuration, the trigger is ignored.
    • When a specific trigger matches this spec (using event_report_windows ). Note that the trigger could still be matched with a source for aggregatable reports despite failing the two match criteria mentioned earlier.
  • A specific algorithm for summarizing and bucketizing all the triggers within an attribution window. This allows triggers to specify a value parameter that gets summed up for a particular spec, but reported as a bucketed value.

Triggers will also support adding an optional value parameter in the dictionaries within event_trigger_data .

{
  "event_trigger_data": [
    {
      "trigger_data": "2",
      "value": 100,  // Defaults to 1
      "filters": ...
    },
    ...
  ]
}

Every trigger registration will match with at most one trigger spec and update its associated summary value. At a high level, at trigger time we will:

  • Apply global attribution filters.
  • For every trigger spec, evaluate the event_trigger_data on the spec to find a match, using the spec's event_reporting_window . The top level event_reporting_windows acts as a default value in case any trigger spec is the missing event_report_windows sub-field.
  • The first matched spec is chosen for attribution, and the summary value is incremented by value .

When the event_report_window for a spec completes, we will map its summary value to a bucket, and send an event-level report for every increment in the summary bucket caused by attributed trigger values. Reports will come with one extra field, trigger_summary_bucket .

{
  ...
  "trigger_summary_bucket": [<bucket start>, <bucket end>],
}

Configurations that are equivalent to the current version

The following are equivalent configurations for the APIs current event and navigation sources, respectively. Especially for navigation sources, this illustrates why the noise levels are so high relative to event sources to maintain the same epsilon values: navigation sources have a much larger output space.

It is possible that there are multiple configurations that are equivalent, given that some parameters can be set as default or pruned.

Equivalent event sources
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1],
    "event_report_windows": {
      "end_times": [<30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1],
  }],
  "max_event_level_reports": 1,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}
Equivalent navigation sources
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3, 4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [<2 days>, <7 days>, <30 days>]
    },
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3],
  }],
  "max_event_level_reports": 3,
  ...
  // expiry must be greater than or equal to the last element of the end_times
  "expiry": <30 days>,
}

Example custom configurations

Below are some additional configurations outside the defaults. In all of these examples, the developer trade-offs include:

  • reducing some dimension of the default configuration (#triggers, trigger data cardinality, #windows) for increasing another one to preserve the noise level
  • reducing some dimension of the default configuration (#triggers, trigger data cardinality, #windows) for reduced noise level

Report trigger value buckets

This example configuration supports a developer who wants to optimize for value data for only one reporting window (eg 7 days), trading fewer reporting windows for less noise. In this example any trigger that sets trigger_data to a value other than 0 is ineligible for attribution.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
    },
    "summary_window_operator": "value_sum",
    "summary_buckets": [5, 10, 100]
  }],
}

Triggers could be registered with the value field set, which are summed up and bucketed. For example if there are three triggers within 7 days of source registrations with values 1, 3 and 4.

{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }

The values are summed to 8 and reported in the following reports after 7 days + 1 hour:

// Report 1
{
  ...
  "trigger_summary_bucket": [5, 9]
}

In the subsequent 7 days, the following triggers are registered:

{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }

The values are summed to 8 + 50 + 45 = 103. This yields the following reports at 14 days + 1 hour:

// Report 2
{
  ...
  "trigger_summary_bucket": [10, 99]
},

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Report trigger counts

This example shows how a developer can configure a source to get a count of triggers up to 10.

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800] // 7 days represented in seconds
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }],
}

Attributed triggers with trigger_data set to 0 are counted and capped at 10. The trigger value is ignored since summary_window_operator is set to count. If 4 triggers are registered and attributed to the source, the report would look like this:

// Report 1
{
  ...
  "trigger_summary_bucket": [1, 1]
}
// Report 2
{
  ...
  "trigger_summary_bucket": [2, 2]
}
// Report 3
{
  ...
  "trigger_summary_bucket": [3, 3]
}
// Report 4
{
  ...
  "trigger_summary_bucket": [4, 4]
}
Binary with more frequent reporting

This example configuration supports a developer who wants to learn whether at least one conversion occurred in the first 10 days (regardless of value), but wants to receive reports at more frequent intervals than the default. Again, in this example any trigger that sets trigger_data to a value other than 0 is ineligible for attribution. This is why this use case is referred to as binary .

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      // 1 day, 2 days, 3 days, 5 days, 7 days, 10 days represented in seconds
      "end_times": [86400, 172800, 259200, 432000, 604800, 864000]
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1]
  }],
}
Vary trigger specs from source to source
{
  "trigger_specs": [
  {
    "trigger_data": [0, 1, 2, 3],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}
{
  "trigger_specs": [
  {
    "trigger_data": [4, 5, 6, 7],
    "event_report_windows": {
      "end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
    }
  }],
  "max_event_level_reports": 3
}

We encourage developers to suggest different use cases they may have for this API extension, and we will update this explainer with sample configurations for those use cases.

Cross network attribution without redirects

Ad techs should use redirects to register multiple attribution source triggers and to perform cross-network attribution. This feature helps support cross-network attribution where redirects aren't feasible across networks. بیشتر بدانید .

Ad techs can send configuration in the trigger registration response based on which sources registered by other ad techs are selected to generate derived sources; these derived sources are then used for attribution. Aggregate reports are generated if the trigger gets attributed to a derived source. Event report generation for derived sources is not supported.

Ad techs can choose from the aggregation_keys in their registered sources that they intend to share with partner ad techs. These keys can be declared in the optional shared_aggregation_keys field, located under the source registration header Attribution-Reporting-Register-Source :

"shared_aggregation_keys": ["[key name1]", "[key name2]"]

Derived sources are generated based on the configuration under the trigger registration header Attribution-Reporting-Register-Trigger :

  // Specifies the configuration based on which derived sources should be
  // generated. Those derived sources will be included for source matching at the
  // time of attribution. For example, if adtech2 is registering a trigger with an
  // attribution_config with source_network as adtech1, available sources
  // registered by adtech1 will be considered with additional filtering criteria
  // applied to that set as mentioned in the attribution_config. Derived
  // sources can have different values to priority, post_install_exclusivity_window
  // etc.

  "attribution_config": [
    {
      // Derived sources are created from this adtech's registered sources
      "source_network": "[original source's adtech enrollment ID]",
      //(optional) Filter sources whose priority falls in this range
      "source_priority_range": {
        "start": [priority filter lower bound],
        "end": [priority filter upper bound]
      },
      // (optional) Filter sources whose at least one of filter maps matches these
      // filters
      "source_filters": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) Filter sources whose none of filter map matches these
      // filters
        "source_not_filters": {
          "key name 1": ["key1 value 1"]
        },
      // (optional) Apply this priority to the generated derived sources
      "priority": "[64 bit signed integer]",
      // (optional) The derived source will have expiry set as this or parent
      // source's, whichever is earlier
      "expiry": "[64 bit signed integer]",
      // (optional) set on the derived source
      "filter_data": {
        "key name 1": ["key1 value 1"]
      },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "[64-bit unsigned integer]"
    }
  ]

Here's a version with example values added:

  "attribution_config": [
    {
      "source_network": "adtech1-enrollment-id",
      "source_priority_range": {
        "start": 50,
        "end": 100
      },
      "source_filters": {
        "source_type": ["NAVIGATION"]
      },
      "source_not_filters": {
        "product_id": ["789"]
      },
      "priority": "30",
      "expiry": "78901",
      // (optional) set on the derived source
      "filter_data": {
        "product_id": ["1234"]
        },
      // (optional) set on the derived source
      "post_install_exclusivity_window": "7890"
    }
  ]

Two new optional fields are added to trigger registration header. These fields enable the winning ad tech's identifier in aggregatable report keys:

  • x_network_bit_mapping : Enrollment id to ad tech identifier bit mapping
  • x_network_data : Offset (left shift) for the winning ad tech's x_network_bit_mapping OR operation with the trigger key piece
مثال:
"Attribution-Reporting-Register-Trigger": {
  "attribution_config": [...],
  "aggregatable_trigger_data": [
    {
     "key_piece": "0x400",
     "source_keys": ["campaignCounts"]
      "x_network_data" : {
        "key_offset" : 12 // [64 bit unsigned integer]
      }
    }
    …
  ]
  …
  "x_network_bit_mapping": {
   // This mapping is used to generate trigger key pieces with AdTech identifier
   // bits. eg. If AdTechA's sources wins the attribution then 0x1 here will be
   // OR'd with the trigger key pieces to generate the final key piece.
    "AdTechA-enrollment_id": "0x1", // Identifier bits in hex for A
    "AdTechB-enrollment_id": "0x2"  // Identifier bits in hex for B
  }
  …
}

Here's the resulting trigger key piece calculation when generating a report for AdTechB's source:

  • key_piece : 0x400 (010000000000)
  • key_offset : 12
  • AdtechB's enrollment_id value: 2 (010) (from x_network_bit_mapping )
  • Resultant Trigger Key piece: 0x400 | 0x2 << 12 = 0x2400

محدودیت ها

For a list of in-progress capabilities for the SDK Runtime, view the release notes .

اشکالات و مشکلات را گزارش کنید

Your feedback is a crucial part of the Privacy Sandbox on Android! Let us know of any issues you find or ideas for improving Privacy Sandbox on Android.