> Detailed guide for LinkedIn Ads operations via the LinkedIn Marketing API.
This agent helps you create and manage LinkedIn Ads campaigns through the Marketing API. Use it to set up targeted B2B campaigns, track performance analytics, and handle OAuth authentication for ad operations.
/plugin marketplace add robynnai/robynn-claude-cmo/plugin install robynnai-rory@robynnai/robynn-claude-cmoDetailed guide for LinkedIn Ads operations via the LinkedIn Marketing API.
LinkedIn Ads uses this hierarchy:
Ad Account
└── Campaign Group (optional - for budget/schedule grouping)
└── Campaign (objective, targeting, budget)
└── Creative (ad content)
Create LinkedIn App:
1. Go to https://www.linkedin.com/developers/apps
2. Click "Create app"
3. Fill in app details
4. Add "Marketing Developer Platform" product
5. Complete access request form
Configure OAuth:
1. In app settings, go to "Auth" tab
2. Add redirect URL: http://localhost:8080/callback
3. Note Client ID and Client Secret
4. Request these scopes:
- r_ads (read ads)
- rw_ads (read/write ads)
- r_ads_reporting (analytics)
Generate Access Token:
# Use the LinkedIn auth helper
python linkedin_ads_auth.py
# Follow browser prompts to authorize
# Token is valid for 60 days
Find Ad Account ID:
# List your ad accounts
python linkedin_ads.py accounts
Configure Environment:
# .env file
LINKEDIN_CLIENT_ID=your_client_id
LINKEDIN_CLIENT_SECRET=your_client_secret
LINKEDIN_ACCESS_TOKEN=your_access_token
LINKEDIN_AD_ACCOUNT_ID=123456789
| Type | API Value | Use For |
|---|---|---|
| Sponsored Content | TEXT_AD | Feed posts |
| Message Ads | SPONSORED_INMAILS | Direct messages |
| Dynamic Ads | DYNAMIC | Personalized ads |
| Text Ads | TEXT_AD | Sidebar text ads |
| Objective | API Value | Optimization |
|---|---|---|
| Brand Awareness | BRAND_AWARENESS | Impressions |
| Website Visits | WEBSITE_VISITS | Clicks |
| Engagement | ENGAGEMENT | Social actions |
| Video Views | VIDEO_VIEWS | Views |
| Lead Generation | LEAD_GENERATION | Form fills |
| Website Conversions | WEBSITE_CONVERSIONS | Conversions |
| Job Applicants | JOB_APPLICANTS | Applications |
LinkedIn's B2B targeting is its key differentiator:
| Facet | Description | Example |
|---|---|---|
titles | Job titles | "VP of Marketing" |
titlesSeniority | Seniority level | "VP", "Director", "Manager" |
functions | Job function | "Marketing", "Sales" |
industries | Company industry | "Computer Software" |
companySizes | Employee count | "51-200", "201-500" |
companies | Specific companies | Company URNs |
skills | Member skills | "Digital Marketing" |
degrees | Education level | "Bachelor's", "Master's" |
fieldsOfStudy | Study field | "Business Administration" |
schools | Universities | School URNs |
| Facet | Description |
|---|---|
locations | Countries, states, cities |
geoURNs | Geographic URN codes |
| Option | Description |
|---|---|
enableAudienceExpansion | Let LinkedIn find similar audiences |
excludedAudienceExpansion | Expand exclusions |
python linkedin_ads.py accounts
API Call:
GET https://api.linkedin.com/rest/adAccounts?q=search
python linkedin_ads.py campaigns --account-id 123456789
API Call:
GET https://api.linkedin.com/rest/adCampaigns?q=search&search=(account:(values:List(urn:li:sponsoredAccount:123456789)))
python linkedin_ads.py analytics --campaign-id 123456 --days 30
API Call:
GET https://api.linkedin.com/rest/adAnalytics?q=analytics
&pivot=CAMPAIGN
&dateRange=(start:(year:2024,month:1,day:1),end:(year:2024,month:1,day:31))
&campaigns=List(urn:li:sponsoredCampaign:123456)
&fields=impressions,clicks,costInLocalCurrency,externalWebsiteConversions
⚠️ Safety: All campaigns created via API are set to DRAFT status.
python linkedin_ads.py create \
--account-id 123456789 \
--name "LinkedIn - VP Marketing" \
--objective WEBSITE_VISITS \
--budget 100.00 \
--targeting "titles:VP of Marketing,CMO;industries:Computer Software"
python linkedin_ads.py update \
--campaign-id 123456 \
--budget 150.00
# List available targeting facets
python linkedin_ads.py targeting --facets
# Search for specific targeting values
python linkedin_ads.py targeting --search "Marketing" --facet titles
campaign_config = {
"account": "urn:li:sponsoredAccount:123456789",
"name": "Sponsored Content - Q1 2024",
"status": "DRAFT", # Always DRAFT
"type": "SPONSORED_UPDATES",
"objectiveType": "WEBSITE_VISITS",
"costType": "CPC",
"unitCost": {
"currencyCode": "USD",
"amount": "5.00" # Max CPC bid
},
"dailyBudget": {
"currencyCode": "USD",
"amount": "100.00"
},
"totalBudget": {
"currencyCode": "USD",
"amount": "3000.00"
},
"runSchedule": {
"start": 1704067200000, # Unix timestamp ms
"end": 1706745600000
},
"targetingCriteria": {
"include": {
"and": [
{
"or": {
"urn:li:adTargetingFacet:titles": [
"urn:li:title:123", # VP of Marketing
"urn:li:title:456" # CMO
]
}
},
{
"or": {
"urn:li:adTargetingFacet:industries": [
"urn:li:industry:4" # Computer Software
]
}
},
{
"or": {
"urn:li:adTargetingFacet:companySizes": [
"urn:li:companySizeRange:(51,200)",
"urn:li:companySizeRange:(201,500)"
]
}
}
]
}
},
"locale": {
"country": "US",
"language": "en"
}
}
campaign_config = {
"account": "urn:li:sponsoredAccount:123456789",
"name": "Lead Gen - Whitepaper Download",
"status": "DRAFT",
"type": "SPONSORED_UPDATES",
"objectiveType": "LEAD_GENERATION",
"optimizationTargetType": "MAX_LEAD",
"costType": "CPM",
"dailyBudget": {
"currencyCode": "USD",
"amount": "150.00"
},
# Lead gen form must be created separately
"associatedEntity": "urn:li:organization:12345"
}
creative_config = {
"campaign": "urn:li:sponsoredCampaign:123456",
"status": "DRAFT",
"type": "SPONSORED_STATUS_UPDATE",
"variables": {
"data": {
"com.linkedin.ads.SponsoredUpdateCreativeVariables": {
"activity": "urn:li:activity:123456789", # LinkedIn post URN
# OR create new content:
"content": {
"contentEntities": [
{
"entityLocation": "https://example.com/landing",
"thumbnails": [
{"resolvedUrl": "https://example.com/image.jpg"}
]
}
],
"title": "Ad Headline Here",
"description": "Ad description text"
},
"commentary": "Introductory text that appears above the ad"
}
}
}
}
| Metric | Description |
|---|---|
impressions | Times ad was shown |
clicks | Total clicks |
costInLocalCurrency | Spend in account currency |
externalWebsiteConversions | Website conversions |
leadGenerationMailContactInfoShares | Lead form submits |
reactions | Post reactions |
comments | Post comments |
shares | Post shares |
follows | Page follows |
videoViews | Video views |
videoCompletions | Full video watches |
| Pivot | Description |
|---|---|
CAMPAIGN | By campaign |
CREATIVE | By creative/ad |
COMPANY | By company (ABM) |
MEMBER_INDUSTRY | By member industry |
MEMBER_SENIORITY | By seniority level |
MEMBER_JOB_FUNCTION | By job function |
Before launching, check audience size:
python linkedin_ads.py audience-count --targeting "titles:VP Marketing;industries:Software"
API Call:
POST https://api.linkedin.com/rest/adTargetingEstimates
{
"targetingCriteria": { ... },
"campaignType": "SPONSORED_UPDATES"
}
Response:
{
"totalCount": 45000,
"activeCount": 38000
}
⚠️ Note: LinkedIn requires minimum 300 audience members for campaigns to run.
| Issue | Cause | Solution |
|---|---|---|
UNAUTHORIZED | Token expired | Regenerate access token (60-day expiry) |
FORBIDDEN | Missing permissions | Check app has rw_ads scope |
AUDIENCE_TOO_SMALL | < 300 members | Broaden targeting criteria |
INVALID_URN | Wrong URN format | Use correct URN syntax |
RATE_LIMITED | Too many requests | Implement backoff |
LinkedIn uses URNs (Uniform Resource Names):
urn:li:sponsoredAccount:123456789
urn:li:sponsoredCampaign:123456
urn:li:sponsoredCreative:123456
urn:li:organization:123456
urn:li:title:123
urn:li:industry:4
LinkedIn Marketing API uses dated versions:
Header: LinkedIn-Version: 202401
Always specify version to avoid breaking changes. Current stable: 202401
Check recent changes: https://learn.microsoft.com/en-us/linkedin/marketing/integrations/recent-changes
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences