Skip to main content

Overview

This quickstart guide will walk you through making your first API call to the Cross-Media Measurement API. By the end of this guide, you’ll have authenticated with the API and created your first measurement request.
This guide assumes you have access to the Cross-Media Measurement system. Contact your Kingdom operator if you need access credentials.

Prerequisites

Before you begin, ensure you have:
1

Development Environment

  • A programming language with gRPC support (Python, Java, Go, or C++)
  • Protocol Buffer compiler (protoc)
  • Basic understanding of gRPC and Protocol Buffers
2

API Access

  • Account credentials for the Kingdom
  • A MeasurementConsumer creation token (obtained from Kingdom operator)
  • Access to the API endpoint URL
3

Cryptographic Tools

  • OpenSSL or similar tool for generating X.509 certificates
  • Understanding of public/private key cryptography

Step 1: Set Up Your Environment

First, clone the API repository to get the Protocol Buffer definitions:
git clone https://github.com/world-federation-of-advertisers/cross-media-measurement-api.git
cd cross-media-measurement-api

Generate Client Code

Use the Protocol Buffer compiler to generate client code for your preferred language:
# Generate Python client code
python -m grpc_tools.protoc \
  --proto_path=src/main/proto \
  --python_out=. \
  --grpc_python_out=. \
  src/main/proto/wfa/measurement/api/v2alpha/*.proto

Step 2: Authenticate

The API uses OpenID Connect for authentication. Follow these steps to obtain an ID token:
1

Call the Authenticate Method

Call the Authenticate RPC to get an authentication request URI:
from wfa.measurement.api.v2alpha import accounts_pb2, accounts_pb2_grpc

# Connect to the API
channel = grpc.secure_channel(
    'kingdom.example.com:443',
    grpc.ssl_channel_credentials()
)
stub = accounts_pb2_grpc.AccountsStub(channel)

# Request authentication
request = accounts_pb2.AuthenticateRequest()
response = stub.Authenticate(request)

print(f"Navigate to: {response.authentication_request_uri}")
2

Complete OpenID Flow

Navigate to the returned URI in a web browser and complete the authentication flow with your identity provider.
3

Extract the ID Token

After successful authentication, extract the ID token from the authentication response. This token will be used in subsequent API calls.

Step 3: Create a MeasurementConsumer

Before you can create measurements, you need to register as a MeasurementConsumer:
from wfa.measurement.api.v2alpha import measurement_consumers_pb2
from wfa.measurement.api.v2alpha import measurement_consumers_pb2_grpc
from wfa.measurement.api.v2alpha import crypto_pb2

# Generate a certificate for your MeasurementConsumer
# (In production, use proper certificate generation)
certificate_der = generate_certificate()  # Your certificate generation logic

# Prepare the request
request = measurement_consumers_pb2.CreateMeasurementConsumerRequest(
    measurement_consumer=measurement_consumers_pb2.MeasurementConsumer(
        certificate_der=certificate_der,
        display_name="My First Measurement Consumer"
    ),
    measurement_consumer_creation_token="your-creation-token-here"
)

# Add authentication metadata
metadata = [('authorization', f'Bearer {id_token}')]

# Create the MeasurementConsumer
stub = measurement_consumers_pb2_grpc.MeasurementConsumersStub(channel)
mc = stub.CreateMeasurementConsumer(request, metadata=metadata)

print(f"Created MeasurementConsumer: {mc.name}")
Save the MeasurementConsumer resource name - you’ll need it to create measurements.

Step 4: Create Your First Measurement

Now you’re ready to create a measurement! Let’s create a simple reach measurement:
from wfa.measurement.api.v2alpha import measurements_pb2
from wfa.measurement.api.v2alpha import measurements_pb2_grpc
from wfa.measurement.api.v2alpha import measurement_spec_pb2

# Build the measurement specification
measurement_spec = measurement_spec_pb2.MeasurementSpec(
    measurement_public_key=public_key,
    reach_and_frequency=measurement_spec_pb2.MeasurementSpec.ReachAndFrequency(
        reach_privacy_params=measurement_spec_pb2.MeasurementSpec.DifferentialPrivacyParams(
            epsilon=0.01,
            delta=1e-12
        ),
        frequency_privacy_params=measurement_spec_pb2.MeasurementSpec.DifferentialPrivacyParams(
            epsilon=0.01,
            delta=1e-12
        )
    ),
    vid_sampling_interval=measurement_spec_pb2.MeasurementSpec.VidSamplingInterval(
        start=0.0,
        width=0.5  # Sample 50% of VIDs
    )
)

# Create the measurement
request = measurements_pb2.CreateMeasurementRequest(
    parent=mc.name,  # Your MeasurementConsumer name
    measurement=measurements_pb2.Measurement(
        measurement_consumer_certificate=certificate_name,
        measurement_spec=measurement_spec.SerializeToString(),
        data_providers=[
            # Specify your data providers and event groups here
        ]
    ),
    request_id="unique-request-id"  # For idempotency
)

stub = measurements_pb2_grpc.MeasurementsStub(channel)
measurement = stub.CreateMeasurement(request, metadata=metadata)

print(f"Created Measurement: {measurement.name}")
print(f"State: {measurement.state}")

Step 5: Check Measurement Status

Measurements are processed asynchronously. Poll the measurement status to check progress:
import time

def wait_for_measurement(measurement_name):
    stub = measurements_pb2_grpc.MeasurementsStub(channel)
    
    while True:
        request = measurements_pb2.GetMeasurementRequest(name=measurement_name)
        measurement = stub.GetMeasurement(request, metadata=metadata)
        
        print(f"State: {measurement.state}")
        
        if measurement.state == measurements_pb2.Measurement.SUCCEEDED:
            return measurement
        elif measurement.state == measurements_pb2.Measurement.FAILED:
            print(f"Measurement failed: {measurement.failure}")
            return None
        
        time.sleep(10)  # Poll every 10 seconds

result = wait_for_measurement(measurement.name)
if result:
    print(f"Measurement succeeded!")
    print(f"Result: {result.result}")

Next Steps

Congratulations! You’ve successfully: ✅ Set up your development environment
✅ Authenticated with the API
✅ Created a MeasurementConsumer
✅ Created and monitored your first measurement

Dive Deeper

Core Concepts

Learn about the architecture and key concepts

Authentication Guide

Deep dive into authentication and security

Creating Measurements

Comprehensive guide to measurement creation

API Reference

Explore the complete API documentation

Troubleshooting

Problem: Unable to obtain an ID token.Solutions:
  • Verify your OpenID Provider is configured correctly
  • Check that your redirect URI matches the configured value
  • Ensure your account has the necessary permissions
Problem: CreateMeasurementConsumer returns an error.Solutions:
  • Verify your creation token is valid and unused
  • Check that your certificate is properly formatted X.509 DER
  • Ensure you’re passing valid authentication metadata
Problem: Measurement doesn’t progress beyond PENDING.Solutions:
  • Verify all specified data providers exist
  • Check that event groups have data in the measurement time range
  • Ensure requisitions are being fulfilled by data providers
  • Review the Kingdom logs for detailed error messages
Problem: Cannot connect to the API endpoint.Solutions:
  • Verify the API endpoint URL and port
  • Check that you’re using TLS/SSL credentials
  • Ensure your network allows gRPC traffic
  • Verify the server certificate is trusted

Getting Help

GitHub Repository

Report issues, contribute, or browse the source code

Build docs developers (and LLMs) love