Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Googleads Php Lib Laravel Package

googleads/googleads-php-lib

Official Google Ads API client library for PHP, offering generated service stubs, OAuth2 authentication helpers, reporting utilities, and examples to integrate campaign management and ads data into PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is Google's official SOAP client for the Ad Manager API — not a Laravel package. There's no facade, no auto-discovery, and no config publishing. You wire it up yourself, which is actually fine because it's a thin, generated-code library: one class per API object, one service class per endpoint.

Install

composer require googleads/googleads-php-lib

Requirements are ext-soap, ext-curl, ext-json and a supported PHP version. Verify php -m | grep soap before you waste an hour on auth errors that are actually missing extensions. Note that this library uses "fake major" versioning: 74.0.0 is a routine API-version bump, and a caret constraint like ^74.0 is effectively a hard pin. Treat upgrades as deliberate events, not composer update side effects.

Where to look first

  1. vendor/googleads/googleads-php-lib/examples/AdManager/ — every example is a self-contained, runnable recipe for one service call (GetLineItems.php, RunReport.php, CreateOrders.php). This is the real documentation; the README is thin.
  2. src/Google/AdsApi/AdManager/Util/v202608/ — StatementBuilder, ReportDownloader, Pql, DateRange. These are the only hand-written helpers you'll touch daily.
  3. src/Google/AdsApi/AdManager/v202608/ — generated model classes. Skim for property names and required fields.

Credentials

Service-account JSON keys are the sane choice for a server-side Laravel app (no refresh-token rotation). The conventional setup is an INI file:

[AD_MANAGER]
networkCode = 12345678
applicationName = My Laravel App

[OAUTH2]
jsonKeyFilePath = "/var/www/app/storage/app/admanager-key.json"
scopes = "https://www.googleapis.com/auth/admanager"

The networkCode is the numeric network code from the Ad Manager UI, not the display name.

First use case

Don't start with mutations. Start with NetworkService::getCurrentNetwork() as a smoke test — it validates credentials, the network code, and the API version in one call, and returns timeZone and currencyCode, which you'll need later.

Implementation Patterns

Bind the session once, resolve services per call. Building an AdManagerSession performs auth setup and is expensive. Register it as a singleton in a service provider, reading the INI path from config/services.php, and construct services from it:

$this->app->singleton(AdManagerSession::class, function () {
    return (new AdManagerSessionBuilder())
        ->forConfigurationFile(base_path('adsapi_php.ini'))
        ->enableGzipCompression()
        ->withSoapLogger(new SoapLogger())
        ->build();
});

$this->app->bind(AdManagerServices::class, fn () => new AdManagerServices());

Then in a job or action:

$service = $adManagerServices->get($session, LineItemService::class);

Inject the session, never the service objects — they're stateless wrappers and cheap to resolve.

Wrap everything in your own namespace. App\AdManager\Client (or a set of small action classes) that owns every versioned FQCN. When v202608 becomes v202611, the mechanical find/replace should touch one or two files, not eighty. This is the single highest-leverage design decision with this library.

PQL with bind variables, always.

$statementBuilder = (new StatementBuilder())
    ->where('orderId = :orderId')
    ->orderBy('id ASC')
    ->limit(500)
    ->withBindVariableValue('orderId', (int) $orderId);

do {
    $page = $service->getLineItemsByStatement($statementBuilder->toStatement());
    // ... handle $page->getResults()
    $statementBuilder->increaseOffsetBy(500);
} while ($statementBuilder->getOffset() < $page->getTotalResultSetSize());

Never string-concatenate values into PQL. Use Pql::values() when building IN clauses.

Reports are always queued. ReportService::runReportJob() enqueues on Google's side; ReportDownloader::waitForReportToFinish() then polls with sleeps. That loop can run minutes. Put it in a queued job with a generous $timeout, download to a Storage::path(), then hand off to a second job that parses the CSV. Never do this in a web request.

Bulk mutations in chunks. Fetch the objects with a statement, mutate the returned objects in place (don't hand-build partial objects — required fields and IDs get dropped), and call updateX in batches of a few hundred. Track per-object results because updateX succeeds partially: check getResults() length against input length and log failures individually.

Sync to your own database. The usual production shape is a nightly (or webhook-less scheduled) job that pulls orders/line items/inventory into local tables so dashboards and admin UI never touch the API. Reserve live API calls for writes and for data that must be fresh.

Test against a sandbox network. Ad Manager has test networks; give each developer one and point networkCode at it via .env. Mocking this library is painful because the generated classes are concrete, so behind your App\AdManager wrapper, define interfaces you can fake.

Gotchas and Tips

  • The API version is baked into every class name. Google\AdsApi\AdManager\v202608\LineItem, ...\v202608\StatementBuilder, and the service FQCN all carry it. A library upgrade is a find/replace across your code, plus an update to any StatementBuilder import — mismatching a v202511 StatementBuilder with a v202608 service will throw confusing serialization errors rather than a clean version error.
  • v74.0.0 drops v202508 entirely. If you're pinned there, this release is a hard break: Class not found at runtime, typically first in a queued job rather than in tests. Also note the release removed examples for v202511 while keeping the classes — in this library's cadence that's the two-minute warning: v202511 will disappear in the next release. Schedule the migration now rather than after the outage.
  • New versions appear on Ad Manager's side on Google's schedule. Bumping the library to v202608 before your network's data exposes the new version's fields is fine for reads, but new enum values (e.g. a new LineItemType) will deserialize into nulls if your generated classes lag. Check the release-notes diff for enum and required-field changes, not just the version string.
  • The SOAP logger writes to stdout by default. In an HTTP request that means megabytes of XML dumped into your response and a corrupted JSON payload. Route it through a Monolog channel, or only attach it when app()->environment('local').
  • Errors hide in ApiException. Catch it, iterate $e->getErrors(), and log getErrorString() plus getFieldPath() and getTrigger() — the top-level message ("An error occurred") is useless. UniqueError means a duplicate name, not a retryable failure; SERVER_ERROR and quota reasons are worth exponential backoff.
  • Money is in micro-units. Money::getMicroAmount() returns 1,000,000 per currency unit. Divide on the way in, multiply on the way out, and store integers to avoid float drift on invoiced amounts.
  • Dates are Date value objects, not DateTime. They carry year/month/day in the network's timezone, which you got from getCurrentNetwork(). Comparing them against now() without normalizing timezone produces off-by-one-day bugs in reporting windows.
  • Getters return null constantly. Optional fields, empty SOAP arrays, and [] vs null are all normal. Guard every getX() in your mapping layer or you'll get null-property errors on the one line item that never had a startTime.
  • ReportDownloader writes wherever you point it and doesn't clean up. Use an absolute path under storage/app/, and delete the file after parsing. Large reports (millions of rows) will blow memory if you file_get_contents() them — stream with fgetcsv().
  • Extension points are limited but real: custom Monolog instances for SOAP and report-downloader logging, enableGzipCompression() to cut payload size on big getXByStatement responses (worth the CPU), and subclassing services if you need to instrument call timing. There's no retry middleware — build your own decorator around your App\AdManager wrapper.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core