How to Build an Advertising Dashboard Across Multiple Platforms Using a Unified Advertising API
March 24, 2026
An advertising dashboard shows campaign performance across multiple integrations and allows users to act on that data.
In practice, this is not just a reporting problem. It is a campaign structure and targeting problem.
Each advertising integration defines:
- campaign structure differently
- targeting inputs differently
- identifiers differently
- write behavior differently
This guide shows how to build a cross-platform advertising dashboard that:
- retrieves campaigns and performance data
- segments by ad account
- looks up targeting identifiers
- updates campaigns (status, budgets, dates)
- applies targeting at the correct level
Using the Unified Advertising API.
Why Advertising Dashboards Break
Most teams start with reporting:
- fetch campaigns
- fetch metrics
- display charts
This works for one integration.
It breaks when you support multiple:
- targeting identifiers are incompatible
- campaign fields behave differently
- some integrations allow updates, others don't
- filtering logic becomes inconsistent
The result:
- inconsistent UI
- fragile logic
- increasing maintenance
The issue is not metrics.
The issue is campaign structure + targeting.
How the Advertising Data Model Works
Unified provides a consistent structure across integrations.
| Object | Purpose | Key Fields |
|---|---|---|
| Organization | Ad account | id, name, currency |
| Campaign | Budget + schedule | status, budget, dates |
| Group | Targeting + delivery | targeting, bid |
| Ad | Creative | headline, copy |
| Target | Lookup values | id, name, type |
| Report | Metrics | metrics |
Targeting is:
- readable on campaigns
- configurable primarily at the group level
- supported at campaign level only where the integration allows it
Step 1: Retrieve Ad Accounts
Ad accounts are represented as AdsOrganization.
const organizations = await sdk.ads.listAdsOrganizations({
connectionId,
});
Each organization includes:
idnamecurrencytimezone
Ad account selection happens after authorization, not during OAuth.
Step 2: Retrieve Campaigns
const campaigns = await sdk.ads.listAdsCampaigns({
connectionId,
orgId, // optional
});
Key points:
orgIdfilters by ad account- campaigns are returned using a unified structure
- targeting is included as a readable field
Step 3: Retrieve Performance Data
const reports = await sdk.ads.listAdsReports({
connectionId,
startGte: "2026-01-01",
endLt: "2026-01-31",
});
Each report includes:
organization_idstart_at,end_atmetrics[]
Metrics are integration-defined and should not be hardcoded.
Step 4: Look Up Targeting Identifiers
Before applying targeting, you must retrieve valid IDs.
Each integration uses different identifiers:
Unified provides a lookup endpoint:
const targets = await sdk.ads.listAdsTargets({
connectionId,
type: 'countries',
query: 'united',
limit: 50,
});
Returns:
[
{ "id": "US", "name": "United States", "type": "countries" },
{ "id": "GB", "name": "United Kingdom", "type": "countries" }
]
Supported types include:
- countries, regions, cities
- locales, languages
- interests, behaviors, topics
- user_lists (custom audiences)
- age_ranges, genders
These IDs are used in targeting payloads.
Step 5: Apply Targeting (Group-Level)
For most integrations, targeting is configured at the group level.
const group = await sdk.ads.getAdsGroup({
connectionId,
id: groupId,
});
await sdk.ads.updateAdsGroup({
connectionId,
id: groupId,
adsGroup: {
...group,
targeting: {
geographic: {
countries: ['US'],
regions: [{ id: '3843', name: 'California' }],
},
demographic: {
ageMin: 25,
ageMax: 54,
male: true,
female: true,
},
audience: {
interests: [
{ id: '600313926646746', name: 'Technology' }
],
},
},
},
});
Important:
- IDs come from
listAdsTargets - targeting structure is consistent
- available targeting types vary by integration
Step 6: Update Campaign Controls
Campaign updates use PUT semantics.
Use a read → merge → update pattern.
Pause a campaign
const campaign = await sdk.ads.getAdsCampaign({
connectionId,
id,
});
await sdk.ads.updateAdsCampaign({
connectionId,
id,
adsCampaign: {
...campaign,
status: 'PAUSED',
},
});
Update budget
await sdk.ads.updateAdsCampaign({
connectionId,
id,
adsCampaign: {
...campaign,
budgetAmount: 5000,
budgetPeriod: 'DAILY',
},
});
Update flight dates
await sdk.ads.updateAdsCampaign({
connectionId,
id,
adsCampaign: {
...campaign,
endAt: '2026-03-31T23:59:59Z',
},
});
Dates must be ISO-8601.
Provider Differences You Must Handle
Not all integrations support the same fields.
Examples:
- Some allow campaign-level targeting
- Most require group-level targeting
- Some do not allow budget updates
- Some restrict date changes
When unsupported:
501 Not Implemented
Do not retry these operations.
Rate Limits and Retry Logic
When rate limits are exceeded:
429 Too Many Requests
Recommended approach:
- exponential backoff
- retry only on 429
- avoid retrying validation errors
The SDK does not automatically retry write operations.
How the Dashboard Comes Together
The full data flow:
organizations
→ campaigns
→ reports
→ targets (lookup)
→ groups (targeting)
→ campaign updates
This allows you to:
- display campaigns across integrations
- compare performance
- segment by ad account
- apply targeting consistently
- update campaigns safely
Why Targeting Is the Hardest Part
Campaign metrics are easy to retrieve.
Targeting is not.
Each integration:
- uses different identifiers
- supports different targeting types
- validates inputs differently
Without a lookup layer, you must:
- build mapping logic per integration
- maintain ID dictionaries
- handle edge cases manually
Unified removes that step by providing:
- a targeting lookup endpoint
- a consistent targeting structure
- unified object models
This reduces per-integration logic and simplifies campaign creation.
Key Takeaways
- Advertising dashboards fail due to targeting and campaign structure differences
- Campaigns handle budget and scheduling
- Groups handle targeting for most integrations
- Targeting IDs must be retrieved using
listAdsTargets - Campaign updates require read → merge → update
- Provider support varies and must be handled explicitly
- Targeting is the highest-friction part of campaign management