Skip to main content

A Python client for Apple Search Ads API v5

Project description

Apple Search Ads Python Client

A Python client library for Apple Search Ads API v5, providing a simple and intuitive interface for managing and reporting on Apple Search Ads campaigns.

Features

  • 🔐 OAuth2 authentication with JWT
  • 📊 Campaign performance reporting
  • 🏢 Multi-organization support
  • 💰 Spend tracking by app
  • ⚡ Built-in rate limiting
  • 🐼 Pandas DataFrames for easy data manipulation
  • 🔄 Automatic token refresh
  • 🎯 Type hints for better IDE support
  • ✅ 100% test coverage

Installation

pip install apple-search-ads-client

Quick Start

from apple_search_ads import AppleSearchAdsClient

# Initialize the client
client = AppleSearchAdsClient(
    client_id="your_client_id",
    team_id="your_team_id",
    key_id="your_key_id",
    private_key_path="/path/to/private_key.p8"
)

# Get all campaigns
campaigns = client.get_campaigns()

# Get daily spend for the last 30 days
spend_df = client.get_daily_spend(days=30)
print(spend_df)

Authentication

Prerequisites

  1. An Apple Search Ads account with API access
  2. API credentials from the Apple Search Ads UI:
    • Client ID
    • Team ID
    • Key ID
    • Private key file (.p8)

Setting up credentials

You can provide credentials in three ways:

1. Direct parameters (recommended)

client = AppleSearchAdsClient(
    client_id="your_client_id",
    team_id="your_team_id",
    key_id="your_key_id",
    private_key_path="/path/to/private_key.p8"
)

2. Environment variables

export APPLE_SEARCH_ADS_CLIENT_ID="your_client_id"
export APPLE_SEARCH_ADS_TEAM_ID="your_team_id"
export APPLE_SEARCH_ADS_KEY_ID="your_key_id"
export APPLE_SEARCH_ADS_PRIVATE_KEY_PATH="/path/to/private_key.p8"
client = AppleSearchAdsClient()  # Will use environment variables

3. Private key content

# Useful for environments where file access is limited
with open("private_key.p8", "r") as f:
    private_key_content = f.read()

client = AppleSearchAdsClient(
    client_id="your_client_id",
    team_id="your_team_id",
    key_id="your_key_id",
    private_key_content=private_key_content
)

Usage Examples

Get all organizations

# List all organizations you have access to
orgs = client.get_all_organizations()
for org in orgs:
    print(f"{org['orgName']} - {org['orgId']}")

Get campaign performance report

from datetime import datetime, timedelta

# Get campaign performance for the last 7 days
end_date = datetime.now()
start_date = end_date - timedelta(days=7)

report_df = client.get_campaign_report(
    start_date=start_date,
    end_date=end_date,
    granularity="DAILY"  # Options: DAILY, WEEKLY, MONTHLY
)

# Display key metrics
print(report_df[['date', 'campaign_name', 'spend', 'installs', 'taps']])

Get ad group performance report

# Get ad group performance for a specific campaign
campaign_id = "1234567890"
adgroup_report = client.get_adgroup_report(
    campaign_id=campaign_id,
    start_date="2024-01-01",
    end_date="2024-01-31",
    granularity="DAILY"
)

print(adgroup_report[['date', 'adgroup_name', 'spend', 'installs', 'taps']])

Get keyword performance report

# Get keyword performance for a specific campaign
campaign_id = "1234567890"
keyword_report = client.get_keyword_report(
    campaign_id=campaign_id,
    start_date="2024-01-01",
    end_date="2024-01-31",
    granularity="DAILY"
)

print(keyword_report[['date', 'keyword', 'match_type', 'spend', 'installs']])

Get search term performance report

# Get search term performance for a specific campaign
campaign_id = "1234567890"
search_term_report = client.get_search_term_report(
    campaign_id=campaign_id,
    start_date="2024-01-01",
    end_date="2024-01-31"
)

# Analyze which search terms are converting
print(search_term_report[['search_term', 'search_term_source', 'spend', 'installs']])

# Filter by source (AUTO vs TARGETED)
auto_terms = search_term_report[search_term_report['search_term_source'] == 'AUTO']

Track spend by app

# Get daily spend grouped by app
app_spend_df = client.get_daily_spend_by_app(
    start_date="2024-01-01",
    end_date="2024-01-31",
    fetch_all_orgs=True  # Fetch from all organizations
)

# Group by app and sum
app_totals = app_spend_df.groupby('app_id').agg({
    'spend': 'sum',
    'installs': 'sum',
    'impressions': 'sum'
}).round(2)

print(app_totals)

Get campaigns from all organizations

# Fetch campaigns across all organizations
all_campaigns = client.get_all_campaigns()

# Filter active campaigns
active_campaigns = [c for c in all_campaigns if c['status'] == 'ENABLED']

print(f"Found {len(active_campaigns)} active campaigns across all orgs")

Working with specific organization

# Get campaigns for a specific org
org_id = "123456"
campaigns = client.get_campaigns(org_id=org_id)

# The client will use this org for subsequent requests

Working with ad groups

# Get ad groups for a campaign
campaign_id = "1234567890"
adgroups = client.get_adgroups(campaign_id)

for adgroup in adgroups:
    print(f"Ad Group: {adgroup['name']} (Status: {adgroup['status']})")

API Reference

Client initialization

AppleSearchAdsClient(
    client_id: Optional[str] = None,
    team_id: Optional[str] = None,
    key_id: Optional[str] = None,
    private_key_path: Optional[str] = None,
    private_key_content: Optional[str] = None,
    org_id: Optional[str] = None
)

Methods

Organizations

  • get_all_organizations() - Get all organizations
  • get_campaigns(org_id: Optional[str] = None) - Get campaigns for an organization
  • get_all_campaigns() - Get campaigns from all organizations

Reporting

  • get_campaign_report(start_date, end_date, granularity="DAILY") - Get campaign performance report
  • get_adgroup_report(campaign_id, start_date, end_date, granularity="DAILY") - Get ad group performance report for a campaign
  • get_keyword_report(campaign_id, start_date, end_date, granularity="DAILY") - Get keyword performance report for a campaign
  • get_search_term_report(campaign_id, start_date, end_date) - Get search term performance report for a campaign
  • get_adgroup_search_term_report(campaign_id, adgroup_id, start_date, end_date) - Get search term performance report for an ad group
  • get_daily_spend(days=30, fetch_all_orgs=True) - Get daily spend for the last N days
  • get_daily_spend_with_dates(start_date, end_date, fetch_all_orgs=True) - Get daily spend for date range
  • get_daily_spend_by_app(start_date, end_date, fetch_all_orgs=True) - Get spend grouped by app

Campaign Management

  • get_campaigns_with_details(fetch_all_orgs=True) - Get campaigns with app details
  • get_adgroups(campaign_id) - Get ad groups for a specific campaign

DataFrame Output

All reporting methods return pandas DataFrames for easy data manipulation:

# Example: Calculate weekly totals
daily_spend = client.get_daily_spend(days=30)
daily_spend['week'] = pd.to_datetime(daily_spend['date']).dt.isocalendar().week
weekly_totals = daily_spend.groupby('week')['spend'].sum()

Rate Limiting

The client includes built-in rate limiting to respect Apple's API limits (10 requests per second). You don't need to implement any additional rate limiting.

Error Handling

from apple_search_ads.exceptions import (
    AuthenticationError,
    RateLimitError,
    OrganizationNotFoundError
)

try:
    campaigns = client.get_campaigns()
except AuthenticationError as e:
    print(f"Authentication failed: {e}")
except RateLimitError as e:
    print(f"Rate limit exceeded: {e}")
except Exception as e:
    print(f"An error occurred: {e}")

Best Practices

  1. Reuse client instances: Create one client and reuse it for multiple requests
  2. Use date ranges wisely: Large date ranges may result in slower responses
  3. Cache organization IDs: If working with specific orgs frequently, cache their IDs
  4. Monitor rate limits: Although built-in rate limiting is included, be mindful of your usage
  5. Use DataFrame operations: Leverage pandas for data aggregation and analysis

Requirements

  • Python 3.13 or higher
  • See requirements.txt for package dependencies

Testing

This project maintains 100% test coverage. The test suite includes:

  • Unit tests with mocked API responses
  • Exception handling tests
  • Edge case coverage
  • Legacy API format compatibility tests
  • Comprehensive integration tests

Running Tests

# Run all tests with coverage report
pytest tests -v --cov=apple_search_ads --cov-report=term-missing

# Run tests in parallel for faster execution
pytest tests -n auto

# Generate HTML coverage report
pytest tests --cov=apple_search_ads --cov-report=html

# Run integration tests (requires credentials)
pytest tests/test_integration.py -v

For detailed testing documentation, see TESTING.md.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for a list of changes.

Acknowledgments

  • Apple for providing the Search Ads API
  • The Python community for excellent libraries used in this project

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apple_search_ads_client-2.2.0.tar.gz (26.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apple_search_ads_client-2.2.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file apple_search_ads_client-2.2.0.tar.gz.

File metadata

  • Download URL: apple_search_ads_client-2.2.0.tar.gz
  • Upload date:
  • Size: 26.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for apple_search_ads_client-2.2.0.tar.gz
Algorithm Hash digest
SHA256 213e34873a900ece33b68552d92ef0eebbe8fbf1f654cd2028f10477b9c6ea7f
MD5 2be36f910b70e9d384b390c2a5828ad0
BLAKE2b-256 49b9e50a3d74c125d99c2bb2a3b2cb9a9afd0d452c6c3cf61395749df92bd591

See more details on using hashes here.

File details

Details for the file apple_search_ads_client-2.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for apple_search_ads_client-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 522f882e6c891a0f430e1ae8d7dc60b6f1498c22f396586b2aaf21e90a1adef4
MD5 e52785621c93849c91589c22f50a28a5
BLAKE2b-256 0bbab4fe5bb3edf281cadb1ccca4e435e563ea875668f979c7e5518fcf245e0a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page