Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/guides/integration-advertiser-dataprovider-endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ displayed_sidebar: sidebarAdvertisers
---

import Link from '@docusaurus/Link';
import IntegrationExampleIdentityMap from '../snippets/_integration-example-identity-map.mdx';

# Advertiser/Data Provider Integration to HTTP Endpoints

Expand All @@ -32,6 +33,10 @@ You'll need to set up these values, in the UID2 Portal on the [API Keys](../port
It's very important that you keep these values secure. For details, see [Security of API Key and Client Secret](../getting-started/gs-credentials.md#security-of-api-key-and-client-secret).
:::

## Integration Example

<IntegrationExampleIdentityMap />

## High-Level Steps

At a high level, the steps for advertisers and data providers integrating with UID2 are as follows:
Expand Down
7 changes: 6 additions & 1 deletion docs/guides/integration-advertiser-dataprovider-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ displayed_sidebar: sidebarAdvertisers
---

import Link from '@docusaurus/Link';
import IntegrationExampleIdentityMap from '../snippets/_integration-example-identity-map.mdx';

# Advertiser/Data Provider Integration Overview

Expand All @@ -27,6 +28,10 @@ There are other ways that you can use UID2, outside these use cases. These are j
| Send&nbsp;in&nbsp;conversions | Send raw UID2s as conversion information | Use conversion information for measurement (attribution) or for retargeting via API or pixels. |
| Receive&nbsp;graph&nbsp;data | Receive raw UID2s from graph/data providers via API or pixels | Build graph data. |

## Integration Example

<IntegrationExampleIdentityMap />

## High-Level Steps

At a high level, the steps for advertisers and data providers integrating with UID2 are as follows:
Expand Down Expand Up @@ -191,7 +196,7 @@ For instructions for monitoring for salt bucket rotations, refer to one of the f

- Python SDK: [Monitor Rotated Salt Buckets](../sdks/sdk-ref-python.md#monitor-rotated-salt-buckets).

- Snowflake: [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s).
- Snowflake: [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake-before-july-2025.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s).

- HTTP endpoints: [Monitor for Salt Bucket Rotations for Your Stored Raw UID2s (v2)](integration-advertiser-dataprovider-endpoints.md#monitor-for-salt-bucket-rotations-for-your-stored-raw-uid2s-v2).

Expand Down
6 changes: 3 additions & 3 deletions docs/ref-info/deprecation-schedule.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The latest ZIP file is available in the Assets section at the bottom of the link
| Q3 2024 | [v5.38.104](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.38.104) | 5.38.104 | September 12, 2024 | Mar 31, 2026 |
| Q2 2024 | [v5.37.12](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.37.12) | 5.37.12 | June 12, 2024 | Sep 30, 2025 |

For documentation, see [UID2 Private Operator for AWS Integration Guide](..\guides\operator-guide-aws-marketplace.md).
For documentation, see [UID2 Private Operator for AWS Integration Guide](../guides/operator-guide-aws-marketplace.md).

### Private Operator for GCP

Expand All @@ -55,7 +55,7 @@ The latest ZIP file is linked in the GCP Download column in the following table.
| Q3 2024 | [v5.38.104](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.38.104) | [gcp-oidc-deployment-files-5.38.104.zip](https://github.com/IABTechLab/uid2-operator/releases/download/v5.38.104/gcp-oidc-deployment-files-5.38.104.zip) | September 12, 2024 | Mar 31, 2026 |
| Q2 2024 | [v5.37.12](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.37.12) | [gcp-oidc-deployment-files-5.37.12.zip](https://github.com/IABTechLab/uid2-operator/releases/download/v5.37.12/gcp-oidc-deployment-files-5.37.12.zip) | June 12, 2024 | Sep 30, 2025 |

For documentation, see [UID2 Private Operator for GCP Integration Guide](..\guides\operator-private-gcp-confidential-space.md).
For documentation, see [UID2 Private Operator for GCP Integration Guide](../guides/operator-private-gcp-confidential-space.md).

### Private Operator for Azure

Expand All @@ -69,7 +69,7 @@ The latest ZIP file is linked in the Azure Download column in the following tabl
| Q3 2024 | [v5.38.104](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.38.104) | [azure-cc-deployment-files-5.38.104.zip](https://github.com/IABTechLab/uid2-operator/releases/download/v5.38.104/azure-cc-deployment-files-5.38.104.zip) | September 12, 2024 | Mar 31, 2026 |
| Q2 2024 | [v5.37.12](https://github.com/IABTechLab/uid2-operator/releases/tag/v5.37.12) | [azure-cc-deployment-files-5.37.12.zip](https://github.com/IABTechLab/uid2-operator/releases/download/v5.37.12/azure-cc-deployment-files-5.37.12.zip) | June 12, 2024 | Sep 30, 2025 |

For documentation, see [UID2 Private Operator for Azure Integration Guide](..\guides\operator-guide-azure-enclave.md).
For documentation, see [UID2 Private Operator for Azure Integration Guide](../guides/operator-guide-azure-enclave.md).

<!-- ### Private Operator for AKS

Expand Down
5 changes: 5 additions & 0 deletions docs/sdks/sdk-ref-java.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ displayed_sidebar: docs
---

import Link from '@docusaurus/Link';
import IntegrationExampleIdentityMap from '../snippets/_integration-example-identity-map.mdx';
import POSTIdentityMapImprovements from '../snippets/_post-identity-map-improvements-v3.mdx';

# SDK for Java Reference Guide
Expand Down Expand Up @@ -387,6 +388,10 @@ IdentityMapV3Input mixedInput = new IdentityMapV3Input()
IdentityMapV3Response mixedResponse = client.generateIdentityMap(mixedInput);
```

### Integration Example

<IntegrationExampleIdentityMap />

## Migration From Version Using v2 Identity Map

The following sections provide general information and guidance for migrating to the latest version of this SDK, which references `POST /identity/map` version 3, including:
Expand Down
5 changes: 5 additions & 0 deletions docs/sdks/sdk-ref-python.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ displayed_sidebar: docs
---

import Link from '@docusaurus/Link';
import IntegrationExampleIdentityMap from '../snippets/_integration-example-identity-map.mdx';

# SDK for Python Reference Guide

Expand Down Expand Up @@ -302,6 +303,10 @@ mixed_input = IdentityMapV3Input()
mixed_response = client.generate_identity_map(mixed_input)
```

### Integration Example
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is the identical copy, same edits and preferably a snippet... same as prior comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a subtle difference for Python SDK vs the others - in other places I say that the pattern is applicable despite the example using Python SDK, here I don't. Not sure it's worth keeping them separate though - happy to make it the same.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aulme that makes sense, thx. But I do think we should have a snippet. I think it'd be OK to still have that line in the Python SDK doc... it's kind of unnecessary data but I don't think it sounds weird. It's just info.

LMK if you want me to do that for you in the branch.


<IntegrationExampleIdentityMap />

## Migration From Version Using v2 Identity Map

The following sections provide general information and guidance for migrating to the latest version of this SDK, which references `POST /identity/map` version 3, including:
Expand Down
9 changes: 9 additions & 0 deletions docs/snippets/_integration-example-identity-map.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!-- Used by 4 docs: guides/integration-advertiser-dataprovider-endpoints.md | guides/integration-advertiser-dataprovider-overview.md | sdks/isdk-ref-java.md | sdks/isdk-ref-python.md -->

import Link from '@docusaurus/Link';

For a complete demonstration of a working integration that includes all the recommended patterns, see the [UID2 Identity Map v3 Integration Example](https://github.com/IABTechLab/uid2docs/blob/main/static/examples/identity-map-integration-example).

The sample uses the Python SDK, but the integration patterns are applicable to any SDK or direct API integration.

For step-by-step setup instructions and to run the example, see the README.md file: [UID2 Integration Technical Sample](https://github.com/IABTechLab/uid2docs/blob/main/static/examples/identity-map-integration-example/README.md).
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import Link from '@docusaurus/Link';
| [2: Store Raw UID2s and Salt Bucket IDs](#2-store-raw-uid2s-and-salt-bucket-ids) | カスタム(適切な方法で)。 |
| [3: Manipulate or Combine Raw UID2s](#3-manipulate-or-combine-raw-uid2s) | カスタム(適切な方法で)。 |
| [4: Send Stored Raw UID2s to DSPs to Create Audiences or Conversions](#4-send-stored-raw-uid2s-to-dsps-to-create-audiences-or-conversions) | カスタム(適切な方法で)。 |
| [5: Monitor for Salt Bucket Rotations for Your Stored Raw UID2s](#5-monitor-for-salt-bucket-rotations-for-your-stored-raw-uid2s) | 以下のいずれかのオプションを使用してください:<ul><li><strong>Python SDK</strong>: Python Reference Guide を参照してください</li><li><strong>Snowflake</strong>: [Snowflake Integration Guide](integration-snowflake.md) の [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s) を参照してください</li><li><strong>Raw HTTP endpoint</strong>: [POST&nbsp;/identity/buckets](../endpoints/post-identity-buckets.md)</li></ul> |
| [5: Monitor for Salt Bucket Rotations for Your Stored Raw UID2s](#5-monitor-for-salt-bucket-rotations-for-your-stored-raw-uid2s) | 以下のいずれかのオプションを使用してください:<ul><li><strong>Python SDK</strong>: Python Reference Guide を参照してください</li><li><strong>Snowflake</strong>: [Snowflake Integration Guide](integration-snowflake.md) の [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake-before-february-2025.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s) を参照してください</li><li><strong>Raw HTTP endpoint</strong>: [POST&nbsp;/identity/buckets](../endpoints/post-identity-buckets.md)</li></ul> |
| [6: Monitor for Opt-Out Status](#6-monitor-for-opt-out-status) | API コールを使用して、[POST /optout/status](../endpoints/post-optout-status.md) エンドポイントにアクセスします。 |

## Integration Diagram
Expand Down Expand Up @@ -124,7 +124,7 @@ raw UID2 は、特定の時点におけるユーザーの識別子です。raw U

- Python SDK: [Monitor Rotated Salt Buckets](../sdks/sdk-ref-python.md#monitor-rotated-salt-buckets).

- Snowflake: [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s).
- Snowflake: [Monitor for Salt Bucket Rotation and Regenerate Raw UID2s](integration-snowflake-before-july-2025.md#monitor-for-salt-bucket-rotation-and-regenerate-raw-uid2s).

- HTTP endpoints: [Monitor for Salt Bucket Rotations for Your Stored Raw UID2s](integration-advertiser-dataprovider-endpoints.md#5-monitor-for-salt-bucket-rotations-for-your-stored-raw-uid2s).

Expand Down
3 changes: 3 additions & 0 deletions static/examples/identity-map-integration-example/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
UID2_BASE_URL=https://operator-integ.uidapi.com
UID2_API_KEY=your_api_key_here
UID2_SECRET_KEY=your_secret_key_here
18 changes: 18 additions & 0 deletions static/examples/identity-map-integration-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Environment variables
.env

# Python cache
__pycache__/
*.pyc

# Virtual environments (legacy and uv)
venv/
.venv/

# uv lock file
uv.lock

# Database files
*.db

.idea
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
123 changes: 123 additions & 0 deletions static/examples/identity-map-integration-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# UID2 Integration Technical Sample

**Complete UID2 integration example demonstrating Identity Map v3 flow.**

This sample shows a pattern for mapping email addresses and phone numbers to UID2 tokens, handling optouts, managing token refresh cycles, and performing a sample attribution analysis based on both current and previous UID2s.

## Project Structure

```
identity-map-integration-example/
├── src/ # Python source code
│ ├── complete_demo.py # End-to-end demo workflow
│ ├── map_identities.py # Core UID2 mapping logic
│ ├── attribution_analysis.py # Attribution analysis example
│ ├── config.py # Configuration loading
│ ├── database.py # Database schema and utilities
│ ├── uid_client_wrapper.py # UID2 client with retry logic
│ └── populate_*.py # Test data generation scripts
├── .env # UID2 credentials (create from .env.example)
├── pyproject.toml # Project configuration
└── README.md # This file
```

## Quick Start

### 1. Install Dependencies
```bash
# Install uv (Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install project dependencies
uv sync
```

### 2. Configure UID2 Credentials
```bash
cp .env.example .env
# Edit .env with your UID2 integration credentials
```

Required `.env` format:
```
UID2_BASE_URL=operator-integ.uidapi.com
UID2_API_KEY=your_api_key_here
UID2_SECRET_KEY=your_secret_key_here
```

### 3. Run Complete Demo
```bash
# Full workflow: test data population → UID2 mapping → attribution analysis
uv run src/complete_demo.py
```

### 4. Run Individual Components
```bash
# Generate test data only
uv run src/populate_test_uid_mappings.py

# Run UID2 mapping only
uv run src/map_identities.py

# Run attribution analysis only
uv run src/attribution_analysis.py
```

## Core UID2 Integration Patterns

### Identity Mapping Workflow

**Key Integration Points:**
1. **Batch Processing** (`src/map_identities.py:build_uid2_input()`) - Process sequential batches of up to 5,000 emails and/or phone numbers per request
2. **Retry Logic** (`src/uid_client_wrapper.py:generate_identity_map_with_retry()`) - Exponential backoff for network resilience
3. **Response Handling** (`src/map_identities.py:process_uid2_response()`) - Process mapped, opted-out, and invalid identifiers

## Sample Database Schema

**Core `uid_mapping` table:**
```sql
CREATE TABLE uid_mapping (
uid_mapping_id INTEGER PRIMARY KEY,
dii TEXT NOT NULL, -- Email or phone (+E.164)
dii_type TEXT NOT NULL, -- 'email' or 'phone'
current_uid TEXT, -- Current UID2 token
previous_uid TEXT, -- Previous UID2 token (only available for 90 days after rotation, afterwards NULL)
refresh_from TIMESTAMP, -- When to refresh mapping
opt_out BOOLEAN DEFAULT FALSE -- The user has opted out, we shouldn't attempt to map this user again
);
```

**Key business logic queries:**
```sql
-- Records needing mapping (never mapped + refresh expired)
SELECT uid_mapping_id, dii, dii_type
FROM uid_mapping
WHERE opt_out = FALSE
AND (current_uid IS NULL OR refresh_from < datetime('now'));

-- Attribution joins using both current and previous UID2s
SELECT * FROM impressions imp
JOIN uid_mapping um ON (imp.uid = um.current_uid OR imp.uid = um.previous_uid)
WHERE um.opt_out = FALSE;
```

## Script Reference

| Script | Purpose | Key Integration Concepts |
|--------|---------|--------------------------------------------------|
| `src/populate_test_uid_mappings.py` | Creates 100k test records | Database schema, DII formatting |
| `src/map_identities.py` | **Core UID2 mapping logic** | Batch processing, retry logic, response handling |
| `src/populate_test_conversions_impressions.py` | Attribution demo data | UID2 token usage in measurement |
| `src/attribution_analysis.py` | Attribution analysis | Cross-UID2 joins, measurement patterns |
| `src/complete_demo.py` | End-to-end workflow | Full integration validation |

## Production Integration Checklist

**Patterns for UID2 Integration:**

✅ **Request Limits**: Maximum 5,000 emails and/or phone numbers per request
✅ **Sequential Processing**: No parallel requests to UID2 service
✅ **Retry Logic**: Exponential backoff for network failures
✅ **Optout Handling**: Permanent exclude opted out users from future processing
✅ **Raw UID2 Refresh**: Re-map raw UID2s when they reach `refresh_from` timestamps
✅ **State Persistence**: Track mapping state
14 changes: 14 additions & 0 deletions static/examples/identity-map-integration-example/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[project]
name = "identity-map-tech-sample-2"
version = "0.1.0"
description = "UID2 Identity Map v3 technical sample demonstrating email/phone to UID2 mapping with proper optout handling"
requires-python = ">=3.13"
dependencies = [
"python-dotenv>=1.0.0",
"uid2-client>=2.6.0",
]

[dependency-groups]
dev = [
"black>=23.0.0",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""
Simple demo of joining impression and conversion data via current and previous UIDs
"""
import sqlite3
import traceback
from database import get_connection


def attribution_analysis(conn: sqlite3.Connection) -> None:
"""Run simple attribution analysis query"""
cursor = conn.cursor()

attribution_query = """
SELECT
imp.impression_id,
conv.conversion_id,
conv.conversion_value,
imp.campaign_id,
um.dii,
um.current_uid
FROM impressions imp
JOIN uid_mapping um ON (imp.uid = um.current_uid OR imp.uid = um.previous_uid)
JOIN conversions conv ON (conv.uid = um.current_uid OR conv.uid = um.previous_uid)
WHERE um.opt_out = FALSE
ORDER BY RANDOM()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we want to order by random here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the demo - we're showing 10 rows, if we don't order by random you'll just see a bunch of rows for the same impression.

LIMIT 10
"""

cursor.execute(attribution_query)
results = cursor.fetchall()

print("Sample Attribution Results:")
print(
f"{'Impression':<12} {'Conversion':<12} {'Value':<10} {'Campaign':<12} {'DII':<40} {'UID':<15}"
)
print("-" * 110)

for row in results:
imp_id, conv_id, value, campaign, dii, uid = row
print(
f"{imp_id:<12} {conv_id:<12} ${value:<9.2f} {campaign:<12} {dii:<40} {uid:<15}"
)


def main():
try:
conn = get_connection()
attribution_analysis(conn)
except Exception as e:
print(f"Attribution analysis failed: {e}")
traceback.print_exc()
finally:
if "conn" in locals():
conn.close()


if __name__ == "__main__":
main()
Loading