Entwicklerleitfaden für die Attribution Reporting API

<ph type="x-smartling-placeholder"></ph>

Beim Lesen der Privacy Sandbox für Android Dokumentation auswählen, klicken Sie auf die Schaltfläche Vorschau für Entwickler oder Beta, um Programmversion, mit der Sie arbeiten, da die Anleitung variieren kann.


Feedback geben

Die Attribution Reporting API wurde entwickelt, um den Datenschutz für Nutzer zu verbessern: Entfernen der Abhängigkeit von dienstleisterübergreifenden Nutzerkennungen und Unterstützung wichtiger Anwendungsfälle für die Attribution und Conversion-Analyse in Apps. Dieser Entwicklerleitfaden wird beschrieben, wie Sie die Attribution Reporting APIs konfigurieren und testen, um Anzeigenklicks, Aufrufe und Conversions durch Aufrufen von Methoden, die die relevanten und Quellen für solche Ereignisse.

In diesem Leitfaden erfahren Sie, wie Sie Serverendpunkte einrichten und eine Clientanwendung erstellen der diese Dienste aufruft. Weitere Informationen zum Gesamtaufbau der Attribution Reporting API im Designvorschlag zur Verfügung.

Wichtige Begriffe

  • Attributionsquellen beziehen sich auf Klicks oder Aufrufe.
  • Trigger sind Ereignisse, die Conversions zugeordnet werden können.
  • Berichte enthalten Daten zu einem Trigger und der zugehörigen Attribution Quelle. Diese Berichte werden als Reaktion auf ausgelöste Ereignisse gesendet. Die Die Attribution Reporting API unterstützt Berichte auf Ereignisebene und aggregierbare Berichte.

Hinweis

Wenn Sie die Attribution Reporting API verwenden möchten, müssen Sie die Daten auf der Server- und Clientseite die in den folgenden Abschnitten aufgeführt sind.

Attribution Reporting API-Endpunkte einrichten

Für die Attribution Reporting API ist eine Reihe von Endpunkten erforderlich, auf die Sie zugreifen können von einem Testgerät oder Emulator. Erstellen Sie jeweils einen Endpunkt für Folgendes: serverseitige Aufgaben:

Es gibt mehrere Methoden zum Einrichten der erforderlichen Endpunkte:

  • Am schnellsten geht es mit der Bereitstellung der OpenAPI v3-Dienstdefinitionen aus unserem Beispielcode auf eine simulierte oder Mikrodienstplattform zu übertragen. Sie können Postman, Prism oder ein anderer Testserver die dieses Format akzeptiert. Jeden Endpunkt bereitstellen und im Blick behalten die URIs zur Verwendung in Ihrer App. Informationen zum Überprüfen der Berichtzustellung finden Sie in den Aufrufen die zuvor auf der simulierten oder serverlosen Plattform vorgenommen wurde.
  • Führen Sie Ihren eigenen eigenständigen Server mit der Spring Boot-basierten Lösung aus. Kotlin-Beispiel Diesen Server bei Ihrem Cloud-Anbieter oder intern bereitstellen und Infrastruktur.
  • Verwenden Sie die Dienstdefinitionen als Beispiele, um die Endpunkte in Ihre vorhandenen System zu verstehen.

Quellenregistrierung akzeptieren

Dieser Endpunkt sollte über einen URI ähnlich dem folgenden adressierbar sein:

https://adtech.example/attribution_source

Wenn eine Client-App eine Attributionsquelle registriert, stellt sie den URI für an diesen Serverendpunkt. Die Attribution Reporting API sendet dann eine Anfrage enthält einen der folgenden Header:

  • Für Klickereignisse:

    Attribution-Reporting-Source-Info: navigation
    
  • Für Anzeigeereignisse:

    Attribution-Reporting-Source-Info: event
    

Konfigurieren Sie Ihren Serverendpunkt so, dass er mit Folgendem antwortet:

// 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>

Hier ein Beispiel mit hinzugefügten Beispielwerten:

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

Wenn Attribution-Reporting-Redirects URIs von Anzeigentechnologie-Partnern enthält, wird der Die Attribution Reporting API sendet dann eine ähnliche Anfrage an jeden URI. Jede Anzeigentechnologie muss der Partner einen Server konfigurieren, der mit folgenden Headern antwortet:

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.

Registrierung für Conversion-Trigger akzeptieren

Dieser Endpunkt sollte über einen URI ähnlich dem folgenden adressierbar sein:

https://adtech.example/attribution_trigger

Wenn eine Client-App ein Triggerereignis registriert, stellt sie den URI für diese Serverendpunkt. Die Attribution Reporting API sendet dann eine Anfrage und fügt einer der folgenden Überschriften:

Konfigurieren Sie Ihren Serverendpunkt so, dass er mit Folgendem antwortet:

// 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>

Hier ein Beispiel mit hinzugefügten Beispielwerten:

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

Pro Aggregationsschlüssel-ID und Filterstring sind maximal 25 Byte zulässig. Dieses dürfen Ihre Zusammenfassungsschlüssel-IDs und Filterstrings nicht mehr als 25 Zeichen. In diesem Beispiel hat campaignCounts 14 Zeichen. Es handelt sich also um einen gültigen Aggregationsschlüssel-ID. 1234 ist 4 Zeichen und ist daher ein gültiger Filterstring. Wenn eine Zusammenfassungsschlüssel-ID oder ein Filterstring 25 Zeichen überschreitet, wird der Trigger ignoriert.

Wenn Attribution-Reporting-Redirect URIs von Anzeigentechnologie-Partnern enthält, wird der Die Attribution Reporting API sendet dann eine ähnliche Anfrage an jeden URI. Jede Anzeigentechnologie muss der Partner einen Server konfigurieren, der mit diesen Headern antwortet:

// 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.

Berichte auf Ereignisebene akzeptieren

Dieser Endpunkt sollte über einen URI adressierbar sein. Siehe Für Datenschutz anmelden Sandbox-Konto. (Der URI lautet die aus dem Ursprung der Server abgeleitet werden, die für die Registrierung der Quelle verwendet werden, Registrierung auslösen.) Verwendung der Beispiel-URIs für Endpunkte, die Quelle akzeptieren Registrierung und Triggerregistrierung akzeptieren, lautet der URI dieses Endpunkts:

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

Konfigurieren Sie diesen Server so, dass er JSON-Anfragen im folgenden Format akzeptiert:

{
  "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]",
}

Mit Schlüsseln zur Fehlerbehebung erhalten Sie zusätzliche Einblicke in Ihre Attributionsberichte. Weitere Informationen zu deren Konfiguration

Aggregierbare Berichte akzeptieren

Dieser Endpunkt sollte über einen URI adressierbar sein. Siehe Für Datenschutz anmelden Sandbox-Konto. (Der URI lautet die aus dem Ursprung der Server abgeleitet werden, die für die Registrierung der Quelle verwendet werden, Registrierung auslösen.) Verwendung der Beispiel-URIs für Endpunkte, die Quelle akzeptieren Registrierung und Triggerregistrierung akzeptieren, lautet der URI dieses Endpunkts:

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

Sowohl die verschlüsselten als auch die unverschlüsselten Felder werden für aggregierbare Felder ausgefüllt. Berichte. Mit den verschlüsselten Berichten können Sie Tests mit der Aggregation Dienst, während das unverschlüsselte Feld einen Einblick in die Art und Weise liefert, wie der Schlüsselwert -Paare strukturieren die Daten.

Konfigurieren Sie diesen Server so, dass er JSON-Anfragen im folgenden Format akzeptiert:

{
  // 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]"
}

Mit Schlüsseln zur Fehlerbehebung erhalten Sie zusätzliche Einblicke in Ihre Attributionsberichte. Weitere Informationen zu deren Konfiguration

Android-Client einrichten

Die Client-App registriert Attributionsquellen und -trigger und aktiviert Berichte auf Ereignisebene und aggregierte Berichte erstellen. Android-Client vorbereiten Gerät oder Emulator für die Verwendung der Attribution Reporting API verwenden:

  1. Richten Sie Ihre Entwicklungsumgebung für die Privacy Sandbox auf Android
  2. Installieren Sie ein System-Image auf einem unterstützten Gerät oder Emulator einrichten, der die Privacy Sandbox auf Ihrem Android
  3. Aktivieren Sie den Zugriff auf die Attribution Reporting API, indem Sie den folgenden ADB-Befehl. Die API ist standardmäßig deaktiviert.

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
  4. Wenn Sie die Attribution Reporting API lokal testen, z. B. Gerät, auf das Sie physisch Zugriff haben), führen Sie diesen Befehl aus, um Registrierung:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. Fügen Sie die Berechtigung ACCESS_ADSERVICES_ATTRIBUTION in Ihr Android- Manifestdatei und Werbedienstkonfiguration für Ihre App erstellen, um Attribution Reporting APIs verwenden:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. Optional: Wenn du Debug-Berichte erhalten möchtest, füge die Parameter ACCESS_ADSERVICES_AD_ID-Berechtigung in deiner Android-Manifestdatei:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. Verweisen Sie im <application>-Element von Ihr Manifest:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. Geben Sie die XML-Ressource für die Anzeigendienste an, auf die im Manifest verwiesen wird, z. B.: res/xml/ad_services_config.xml Weitere Informationen über Berechtigungen für Werbedienste und SDK-Zugriffssteuerung.

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

Anzeigenereignisse registrieren

Ihre App sollte Quellen und Conversions erfassen, sobald sie auftreten, um dass sie ordnungsgemäß gemeldet werden. Die Methoden der Klasse MeasurementManager um Quellenereignisse für die Attribution zu registrieren und Conversion-Trigger.

Ereignis für Attributionsquelle registrieren

Wenn eine Anzeige angesehen oder angeklickt wird, ruft eine Publisher-App registerSource() auf Eine Attributionsquelle wird registriert, wie im Code-Snippet gezeigt.

Die Attribution Reporting API unterstützt folgende Arten von Attributionsquellen Events:

  • Klicks, die normalerweise innerhalb einer Callback-Methode wie der folgenden erfasst werden: onClick() Das entsprechende Triggerereignis tritt normalerweise kurz nach dem Click-Event. Diese Art von Ereignis liefert weitere Informationen zum Nutzer Interaktion und ist daher eine gute Attributionsquelle, um hohe Priorität haben.
  • Ansichten, die normalerweise innerhalb einer Callback-Methode wie der folgenden registriert werden: onAdShown() Das entsprechende Triggerereignis kann Stunden oder Tage auftreten. nach dem Aufrufereignis ein.

Kotlin

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)

Java

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);

Nach der Registrierung gibt die API eine HTTP POST-Anfrage an den Dienstendpunkt aus. an die in attributionSourceUri angegebene Adresse gesendet. Die Leistung des Endpunkts Antwort enthält Werte für destination, source_event_id, expiry und source_priority.

Wenn die ursprüngliche Anzeigentechnologie Quellenregistrierungen teilen möchte, muss die ursprüngliche Der URI der Attributionsquelle kann Weiterleitungen zu anderen AdTech-Endpunkten enthalten. Beschränkungen Regeln für die Weiterleitungen werden in der technischen Vorschlags.

Verkettung von Weiterleitungen in registerSource und registerTrigger. Zusätzlich zum Registrierungs-Header kann der API-Nutzer Stellen Sie jetzt eine HTTP-Weiterleitung als Serverantwort bereit, die einen 302-Status enthält. und „Location“ (Standort) mit der nächsten URL, die Sie aufrufen, um weitere Registrierung.

Nur das „Ziel“ des ersten Besuchs verwendet, in der Verkettung. Für die Anzahl der Besuche gilt dasselbe Limit wie für die „Attribution-Reporting-Weiterleitung“ Header. Diese Weiterleitung wird zusätzlich zum mit der vorhandenen „Attribution-Reporting-Weiterleitung“ und wenn beide vorhanden, „Attribution-Reporting-Weiterleitung“ bevorzugt werden.

Conversion-Triggerereignis registrieren

Rufen Sie in Ihrer App registerTrigger() auf, um ein Conversion-Triggerereignis zu registrieren:

Kotlin

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)

Java

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)

Nach der Registrierung gibt die API eine HTTP POST-Anfrage an den Dienstendpunkt aus. an die in attributionTriggerUri angegebene Adresse gesendet. Die Die Antwort des Endpunkts enthält Werte für Ereignisberichte und aggregierte Berichte.

Wenn die ursprüngliche Anzeigentechnologie-Plattform das Teilen von Triggerregistrierungen zulässt, Der URI kann Weiterleitungen zu URIs enthalten, die zu anderen Anzeigentechnologie-Plattformen gehören. Die Beschränkungen und Regeln für die Weiterleitungen sind in der technischen Vorschlags.

App- und Web-Messungen registrieren

Für den Fall, dass sowohl eine App als auch ein Browser im Inhalt des Nutzers eine Rolle spielen. vom Ursprung bis zum Trigger, gibt es kleine Unterschiede Implementierung der Registrierung von Anzeigenereignissen Wenn ein Nutzer eine Anzeige in einer App sieht und für eine Conversion an einen Browser weitergeleitet wird, die Quelle von der App registriert wird, und die Conversion durch den Webbrowser. Das Gleiche gilt, wenn ein Nutzer die Startseite und zur Conversion an eine App weitergeleitet wird, registriert der Browser und die Conversion wird von der App registriert.

Da es Unterschiede bei der Organisation von Anzeigentechnologien im Web und auf der Android haben wir neue APIs hinzugefügt, um Quellen und Trigger zu registrieren, im Browser platzieren. Der Hauptunterschied zwischen diesen APIs und den entsprechenden dass der Browser den Weiterleitungen folgt, alle browserspezifischen Filtern erstellt und die gültigen Registrierungen durch registerWebSource() oder registerWebTrigger() wird angerufen.

Das folgende Code-Snippet zeigt ein Beispiel für den API-Aufruf, mit dem der Browser registriert eine Attributionsquelle, bevor der Nutzer zu einer App weitergeleitet wird:

Kotlin

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)

Java

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);

Das folgende Code-Snippet zeigt ein Beispiel für den API-Aufruf, mit dem der Browser zum Registrieren einer Conversion, nachdem der Nutzer von der App weitergeleitet wurde:

Kotlin

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)

Java

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);

Rauschen zum Schutz der Privatsphäre hinzufügen

Berichte auf Ereignisebene enthalten Ziel, Attributionsquellen-ID und Trigger. Daten. Sie werden im unverschlüsselten Originalformat an die Berichterstellung gesendet Ursprung. Um die Privatsphäre der Nutzer zu schützen, kann Rauschen hinzugefügt werden, um das um einzelne Nutzende zu identifizieren. Berichte auf Ereignisebene mit Rauschen werden generiert und gemäß dem Differential Privacy-Framework gesendet. Dies sind die Standardwerte für den Rauschprozentsatz für verschiedene Szenarien:

Quelltyp

Wert für Quellziel

Wahrscheinlichkeit des verrauschten Berichts pro Quellenregistrierung

Ansehen

App oder Web

0,0000025

Ansehen

Apps und Web

0,0000042

Klick

App oder Web

0,0024263

Klick

Apps und Web

0,0170218

Messung der In-App-zu-Web-Attribution: Wohin Conversions über Quellen erzielt werden können App- und Web-Ziele verwenden, können Sie in Berichten auf Ereignisebene angeben, in der App oder im Web aufgetreten. Als Ausgleich für diese zusätzlichen Details Die generierten Berichte mit Rauten sind etwa das 7-Fache für Klicks und das ~1,7-Fache für Aufrufe.

Einige AdTechs benötigen keine Berichte auf Ereignisebene, um anzugeben, ob der Trigger in der App oder im Web aufgetreten ist. Anzeigentechnologie-Anbieter können die coarse_event_report_destinations unter der Attribution-Reporting-Register-Source-Header, um Bildrauschen zu reduzieren. Wenn eine Quelle mit das angegebene Feld coarse_event_report_destinations gewinnt die Attribution, das Der daraus resultierende Bericht enthält App- und Webziele, ohne dass an der Stelle, an der der eigentlicher Trigger aufgetreten ist.

In den folgenden Beispielen klickt ein Nutzer auf eine Anzeige und die Quelle wird registriert. mit der API. Der Nutzer führt dann sowohl in der App des Werbetreibenden als auch auf der Website des Werbetreibenden. Beide Conversions werden als Trigger registriert und die dem ersten Klick zugeordnet sind.

Ein klickbasierter HTTP-Header zur Quellenregistrierung:

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"
}

In der App wird mit dem Paketnamen ein Trigger registriert com.advertiser.example:

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

Ein Trigger wird von einem Browser der Website mit der Domain eTLD+1 registriert https://advertiser.com:

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

Die daraus resultierenden Berichte auf Ereignisebene werden generiert. Unter der Annahme, dass beide Trigger werden die folgenden Berichte auf Ereignisebene generiert:

  {
    "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
  }

Berichte erstellen und bereitstellen

Die Attribution Reporting API sendet Berichte an die Endpunkte auf Ihrem Server, Berichte auf Ereignisebene akzeptieren und aggregierbare Berichte

Ausführung von Berichtsjobs erzwingen

Nachdem Sie ein Attributionsquellenereignis registriert oder ein Triggerereignis registriert haben, das System die Ausführung des Berichtsjobs plant. Standardmäßig wird dieser Job alle vier Stunden. Zu Testzwecken können Sie die Ausführung der Berichterstellungsjobs erzwingen oder die Intervalle zwischen den Jobs.

Erzwingen, dass der Attributionsjob ausgeführt wird:

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

Erzwingen, dass der Berichterstellungsjob auf Ereignisebene ausgeführt wird:

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

Erzwingen, dass der aggregierte Berichterstellungsjob ausgeführt wird:

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

Prüfen Sie die Ausgabe in Logcat, um zu sehen, wann die Jobs ausgeführt wurden. Es sollte so aussehen: etwa so aussehen:

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

Zustellung von Berichten erzwingen

Auch wenn die Ausführung des Berichterstellungsjobs erzwungen wird, sendet das System trotzdem Berichte. je nach geplanter Lieferdauer, die von ein paar Stunden bis zu mehreren Tagen. Zu Testzwecken können Sie das Gerätesystem nach den geplanten Verzögerungen liegen muss, um die Berichterstellung zu starten.

Berichte auf dem Server überprüfen

Überprüfen Sie die Zustellung, nachdem die Berichte gesendet wurden. Überprüfen Sie dazu gegebenenfalls die erhaltenen Berichte. z. B. den Serververlauf oder Ihr benutzerdefiniertes System.

Zusammengefassten Bericht decodieren

Beim Empfang eines aggregierten Berichts enthält das Feld debug_cleartext_payload eine unverschlüsselte Version des Gesamtberichts. Diese Version Ihres unverschlüsselt ist, muss er noch decodiert werden.

Im Folgenden findest du ein Beispiel für die Decodierung des Inhalts der debug_cleartext_payload in zwei Schritten: im ersten wird die Base64-Decodierung und im zweiten mit CBOR -Decodierung.

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);
});

Test

Für einen leichteren Einstieg in die Attribution Reporting API können Sie die MeasurementSampleApp-Projekt auf GitHub. Diese Beispielanwendung zeigt, Registrierung der Attributionsquelle und Trigger-Registrierung.

Berücksichtigen Sie für Serverendpunkte die folgenden Referenzressourcen oder Ihre benutzerdefinierten Lösung:

  • MeasurementAdTechServerSpec enthält OpenAPI-Dienstdefinitionen. die auf einer unterstützten simulierten oder auf Mikrodienstplattform bereitgestellt werden kann.
  • MeasurementAdTechServer enthält eine Referenzimplementierung eines simulierten basierend auf der Spring Boot-Anwendung für Google App Engine.

Vorbereitung

Stellen Sie simulierte APIs auf Remote-Endpunkten bereit, auf die über Ihr Testgerät zugegriffen werden kann. Emulator. Informationen zu Tests finden Sie unter MeasurementAdTechServerSpec. und MeasurementAdTechServer.

Zu testende Funktionalität

Geplante Funktionen

Flexible Konfiguration auf Ereignisebene

Die Standardkonfiguration für Berichte auf Ereignisebene wird empfohlen, Dienstprogrammtests, sind aber möglicherweise nicht für alle Anwendungsfälle ideal. Die Zuordnung Die Reporting API unterstützt optionale, flexiblere Konfigurationen, sodass Anzeigen mehr Kontrolle über die Struktur ihrer Berichte auf Ereignisebene den Nutzen der Daten maximieren können. Durch diese zusätzliche Flexibilität werden in zwei Phasen in die Attribution Reporting API eingeführt:

  • Phase 1: Flexible Konfiguration auf Ereignisebene in Lite Teilmenge der Phase 2.
  • Phase 2: Vollständige Version der flexiblen Konfiguration auf Ereignisebene.

Phase 1: Flexible Ereignisebene Lite

Wir fügen die folgenden beiden optionalen Parameter 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>, ...]
  }
}

Beispiel für eine benutzerdefinierte Konfiguration

Diese Beispielkonfiguration unterstützt einen Entwickler, der für wenn Berichte zu früheren Berichtszeiträumen empfangen werden.

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

Phase 2: Vollständig flexible Ereignisebene

Zusätzlich zu den Parametern, die in Phase 1 hinzugefügt wurden, fügen wir ein zusätzlichen optionalen Parameter trigger_specs zu den JSON-Daten 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>, ...]
  }
}

Mit dieser Konfiguration wird der Ausgabebereich der Berichte auf Ereignisebene vollständig angegeben. pro Quellenregistrierung. Für jede Triggerspezifikation wird Folgendes vollständig angegeben:

  • Eine Reihe übereinstimmender Kriterien: <ph type="x-smartling-placeholder">
      </ph>
    • Für welche spezifischen Triggerdaten diese Spezifikation gilt. Diese Quelle ist können nur mit Triggern abgeglichen werden, die einen der angegebenen trigger_data-Werte in trigger_specs. Mit anderen Worten, wenn der Parameter Trigger hätte mit dieser Quelle übereinstimmen, aber der zugehörige trigger_data ist keine Eins der Werte in der Konfiguration der Quelle enthält, wird der Trigger ignoriert.
    • Wenn ein bestimmter Trigger dieser Spezifikation entspricht (mithilfe von event_report_windows. Hinweis: Der Trigger kann weiterhin zugeordnet werden. mit einer Quelle für aggregierte Berichte, obwohl die beiden erfolglos waren. Kriterien zu erfüllen.
  • Ein spezieller Algorithmus zur Zusammenfassung und Einteilung aller Trigger innerhalb Zeitfensters für die Attribution. Damit können Trigger einen value-Parameter angeben die für eine bestimmte Spezifikation addiert, aber als Bucket-Wert gemeldet wird.

Trigger unterstützen auch das Hinzufügen eines optionalen Wertparameters im Wörterbücher in event_trigger_data.

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

Jede Triggerregistrierung stimmt mit höchstens einer Triggerspezifikation und einem Trigger-Update überein zugehörigen Zusammenfassungswerts angezeigt. Auf übergeordneter Ebene werden wir zum Zeitpunkt der Auslösung Folgendes tun:

  • Wenden Sie globale Attributionsfilter an.
  • Werten Sie für jede Triggerspezifikation die event_trigger_data der Spezifikation aus, um eine Übereinstimmung unter Verwendung der event_reporting_window der Spezifikation. Auf der obersten Ebene event_reporting_windows dient als Standardwert für den Fall, dass eine Triggerspezifikation das fehlende Unterfeld event_report_windows.
  • Die erste übereinstimmende Spezifikation wird für die Attribution ausgewählt und der Zusammenfassungswert ist um value erhöht.

Wenn event_report_window für eine Spezifikation abgeschlossen ist, wird die Zusammenfassung zugeordnet. an einen Bucket senden und einen Bericht auf Ereignisebene für jedes Inkrement im Zusammenfassungs-Bucket, der durch zugeordnete Triggerwerte verursacht wird. Die Berichte enthalten eine zusätzliches Feld, trigger_summary_bucket.

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

Konfigurationen, die der aktuellen Version entsprechen

Im Folgenden sehen Sie die äquivalenten Konfigurationen für das aktuelle API-Ereignis und Navigationsquellen. Dies gilt insbesondere für Navigationsquellen. zeigt, warum die Rauschpegel im Verhältnis zu den Ereignisquellen so hoch sind, die gleichen Epsilon-Werte beibehalten: Navigationsquellen haben eine viel größere Ausgabe Leerzeichen.

Es ist möglich, dass es mehrere Konfigurationen gibt, die äquivalent sind. einige Parameter als Standard festgelegt oder gekürzt werden können.

Äquivalente Ereignisquellen
// 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>,
}
Äquivalente Navigationsquellen
// 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>,
}

Beispiele für benutzerdefinierte Konfigurationen

Nachfolgend finden Sie einige zusätzliche Konfigurationen außerhalb der Standardeinstellungen. In allen diesen Bereichen Beispiele für Kompromisse bei der Entwicklung:

  • Reduzieren einer Dimension der Standardkonfiguration (#trigger, Triggerdaten) Kardinalität, #windows), zum Erhöhen eines anderen Werts, um den Geräuschpegel beizubehalten
  • Reduzieren einer Dimension der Standardkonfiguration (#trigger, Triggerdaten) Kardinalität, #windows) zur Reduzierung des Rauschpegels.

Wert-Buckets für Berichtstrigger

Diese Beispielkonfiguration unterstützt einen Entwickler, der den Wert optimieren möchte Daten für nur ein Berichtsfenster (z.B. 7 Tage) und weniger Berichte für weniger Lärm. In diesem Beispiel wird jeder Trigger, der trigger_data auf wenn ein anderer Wert als 0 nicht für die Attribution geeignet ist.

{
  "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]
  }],
}

Trigger können mit dem festgelegten Feld value registriert werden, die addiert und gruppiert. Beispiel: Innerhalb von sieben Tagen nach der Quelle werden drei Trigger ausgelöst. Registrierungen mit den Werten 1, 3 und 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}] }

Die Werte werden summiert zu 8 und werden in den folgenden Berichten nach 7 Tagen + 1 Stunde:

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

In den folgenden sieben Tagen werden die folgenden Trigger registriert:

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

Die Werte werden zu 8 + 50 + 45 = 103 addiert. Daraus ergeben sich folgende Berichte unter 14 Tage + 1 Stunde:

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

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Anzahl der Berichtstrigger

Dieses Beispiel zeigt, wie ein Entwickler eine Quelle konfigurieren kann, um die Anzahl der Trigger bis zu 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]
  }],
}

Zugeordnete Trigger, bei denen der trigger_data auf 0 gesetzt ist, werden gezählt und auf 10 begrenzt. Der Triggerwert wird ignoriert, da summary_window_operator auf „Zählen“ festgelegt ist. Wenn vier Trigger registriert und der Quelle zugeordnet sind, sieht der Bericht wie hier:

// 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]
}
Binär mit häufigeren Berichten

Diese Beispielkonfiguration unterstützt einen Entwickler, der wissen möchte, ob mindestens eine Conversion in den ersten 10 Tagen erfolgt ist (unabhängig vom Wert), aber möchte häufiger Berichte als die Standardeinstellung erhalten. Auch hier gilt: In diesem Beispiel wird jeder Trigger, der trigger_data auf einen anderen Wert als 0 setzt, nicht für die Attribution geeignet. Daher wird dieser Anwendungsfall 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]
  }],
}
Triggerspezifikationen von Quelle zu Quelle variieren
{
  "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
}

Wir empfehlen Entwicklern, verschiedene Anwendungsfälle für diese Methode vorzuschlagen. API-Erweiterung. Wir werden diese Erklärung mit Beispielkonfigurationen für diese Anwendungsfälle.

Netzwerkübergreifende Attribution ohne Weiterleitungen

Anzeigentechnologie-Anbieter sollten Weiterleitungen verwenden, um Trigger für mehrere Attributionsquellen zu registrieren und netzwerkübergreifende Attribution durchführen. Diese Funktion unterstützt netzwerkübergreifende Attribution, wenn Weiterleitungen nicht netzwerkübergreifend möglich sind. Weitere Informationen

Anzeigentechnologie-Anbieter können Konfigurationen in der Triggerregistrierungsantwort senden, die auf welche von anderen Anzeigentechnologien registrierten Quellen für die Generierung abgeleiteter Quellen Diese abgeleiteten Quellen werden dann für die Attribution verwendet. Zusammengefasste Berichte werden generiert, wenn der Trigger einer abgeleiteten Quelle zugeordnet wird. Ereignisbericht Die Generierung von abgeleiteten Quellen wird nicht unterstützt.

Anzeigentechnologie-Anbieter können aus den aggregation_keys in ihren registrierten Quellen auswählen, die die sie an Partner-Anzeigentechnologie-Partner weitergeben möchten. Diese Schlüssel können im optionales shared_aggregation_keys-Feld in der Quellregistrierung Überschrift Attribution-Reporting-Register-Source:

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

Abgeleitete Quellen werden basierend auf der Konfiguration unter dem Trigger generiert Registrierungsheader 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]"
    }
  ]

Hier ist eine Version mit hinzugefügten Beispielwerten:

  "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"
    }
  ]

Es wurden zwei neue optionale Felder hinzugefügt, um den Registrierungsheader auszulösen. Diese Felder Die ID des erfolgreichen Anzeigentechnologie-Anbieters wird in aggregierten Berichtsschlüsseln aktiviert:

  • x_network_bit_mapping: Registrierungs-ID zur Bit-Zuordnung der Anzeigentechnologie-ID
  • x_network_data: Offset (Linksverschiebung) für die erfolgreiche Anzeigentechnologie x_network_bit_mapping-ODER-Vorgang mit dem Schlüsselelement für den Trigger
Beispiel:
"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
  }
  
}

Das Ergebnis der Berechnung des Trigger-Schlüsselteils beim Generieren eines Berichts für Quelle der AdTechB:

  • key_piece: 0x400 (010000000000)
  • key_offset: 12
  • enrollment_id-Wert von AdtechB: 2 (010) (von x_network_bit_mapping)
  • Schlüsselelement für resultierenden Trigger: 0x400 | 0x2 << 12 = 0x2400

Beschränkungen

Eine Liste der laufenden Funktionen für die SDK-Laufzeit finden Sie in der Versionshinweise.

Fehler und Probleme melden

Ihr Feedback ist ein wichtiger Teil der Privacy Sandbox für Android. Teilen Sie uns Ihre Meinung mit. zu allen Problemen, die Sie gefunden haben, oder zu Vorschlägen zur Verbesserung der Privacy Sandbox für Android.