@crvouga/mockingbird-service-google-ads

中文文档
1.12.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 3135

Google Ads v25 and GA4 emulator: GAQL metrics, budget mutations, conversion uploads and analytics events/reports.

原始使用文档
文档目录8 节
  1. Install
  2. Usage
  3. Supported operations
  4. Where Google differs from a common assumption
  5. Controls and failures
  6. API
  7. Verification and scope
  8. Deliberately not modelled

@crvouga/mockingbird-service-google-ads

Local emulators. Real API contracts. Part of Mockingbird.

A wip portable emulator for Google Ads API v25 and Google Analytics 4. It provides deterministic GAQL reporting, campaign-budget mutations, click-conversion uploads, Measurement Protocol event collection, and Analytics Data reports using namespaced SQLite state and an injected clock.

Install

bun add @crvouga/mockingbird-service-google-ads

Usage

import { OAuth2Client } from "google-auth-library"
import { DEFAULT_CUSTOMER, DEFAULT_TOKEN } from "@crvouga/mockingbird-service-google-ads"
import { createServer } from "@crvouga/mockingbird-service-google-ads/server"

const emulator = await createServer()

// Google publishes no Node client for the Ads API, so the application calls REST through
// google-auth-library. Only the base URL and the fixture token change.
const client = new OAuth2Client()
client.setCredentials({ access_token: DEFAULT_TOKEN })
const response = await client.request({
  url: `${emulator.url}/v25/customers/${DEFAULT_CUSTOMER}/googleAds:search`,
  method: "POST",
  data: { query: "SELECT campaign.id, campaign.name, metrics.clicks FROM campaign" },
})
console.log(response.data)

await emulator.close()

The Ads and Analytics Data routes use OAuth Bearer credentials. Measurement Protocol routes use the measurement_id and api_secret query parameters. The exported defaults are synthetic and safe for tests. Configure tokens, customers, campaigns, budgets, conversion actions, metrics, and Analytics properties through createRuntime options when a suite needs different fixtures.

For parallel tests, send x-mockingbird-namespace, use the shared /__admin/ns/{namespace} path, or register credentials with the shared admin API. State, pagination snapshots, IDs, clocks, faults, and resets are isolated by namespace.

Supported operations

OperationRouteBehavior
SearchGoogleAdsPOST /v25/customers/{customerId}/googleAds:searchGAQL selection, filtering, ordering, aggregation, summary rows, fixed 10,000-row pages, two-hour page tokens bound to the query, and validate-only requests
SearchStreamGoogleAdsPOST /v25/customers/{customerId}/googleAds:searchStreamDeterministic JSON batches and optional summary rows
MutateCampaignBudgetsPOST /v25/customers/{customerId}/campaignBudgets:mutateCreate, update, remove, update masks, validate-only and atomic or partial failure
UploadClickConversionsPOST /v25/customers/{customerId}:uploadClickConversionsClick identifiers, conversion actions, duplicate detection, job IDs and partial failure
CollectAnalyticsEventsPOST /mp/collectProduction-style empty 204 response with accepted events stored for reporting
ValidateAnalyticsEventsPOST /debug/mp/collectValidation messages without ingestion
RunAnalyticsReportPOST /v1beta/properties/{propertyId}:runReportDimensions, metrics, filters, ordering, pagination and reporting lag
BatchRunAnalyticsReportsPOST /v1beta/properties/{propertyId}:batchRunReportsUp to five report requests

The exact request and response schemas are in openapi.yaml, and the generated support matrix is in SUPPORT.md.

Campaign budgets are read back with GAQL (FROM campaign_budget); uploaded conversions and collected events are read through the inspection routes below, and events also through the Analytics Data reports. REST rows use protobuf JSON names (costMicros, conversionsValue, conversionActionCategory) and int64 values are strings; GAQL field names stay snake_case.

Google Ads failures are a google.rpc.Status whose details hold a GoogleAdsFailure with the per-operation errorCode, message, location and a requestId equal to the request-id response header. Unparsable JSON and every Analytics Data failure are a bare status with no Ads detail and no request-id header.

Where Google differs from a common assumption

These follow Google's documentation and the pinned googleapis v25 protos rather than what a client written against an older contract may expect.

  • Search page size is fixed. Search returns pages of up to 10,000 rows and a request that sets pageSize is rejected with requestError: PAGE_SIZE_NOT_SUPPORTED. Continue by re-sending the identical query with pageToken; a changed query is INVALID_PAGE_TOKEN and a token unused for two hours is EXPIRED_PAGE_TOKEN (paging guide, SearchGoogleAdsRequest). To page a small fixture, lower the emulator's page with the searchPageSize setting; the request still cannot choose it.
  • /mp/collect never reports validation errors over HTTP. It answers an empty 204 for a bad secret, an unparsable body or a rejected event alike. Inspect a rejection with POST /debug/mp/collect, which returns validationMessages and stores nothing, or with GET /__admin/request-metadata, which records accepted, rejected, duplicate and reasons per request (validation guide).
  • Timestamps older than 72 hours are overridden, not rejected, unless the request sets validation_behavior: "ENFORCE_RECOMMENDATIONS" (sending guide). Google documents no bound for future timestamps, so the one-minute futureToleranceMs default is a test policy of this emulator, not a vendor rule; set it to null to disable it.
  • A validate-only budget mutation returns errors only. A valid preflight answers {} with no results and writes nothing (MutateCampaignBudgetsRequest).
  • Mutations take no idempotency key. The duplicate guards are Google's own: a shared budget name (campaignBudgetError: DUPLICATE_NAME), a conversion orderId (ORDER_ID_ALREADY_IN_USE), a click and conversion time (CLICK_CONVERSION_ALREADY_EXISTS), and a web purchase event's transaction_id per user.
  • developer-token is accepted and ignored. The pinned protos mark the developer-token errors as sunset; login-customer-id is still checked against the customer's manager.

Controls and failures

Service-specific controls are protected by the shared x-mockingbird-admin-key guard and live beside the shared health, state, clock, journal, fault, reset, and Timeline endpoints.

ControlPurpose
GET /__admin/eventsInspect stored Analytics events, oldest first
GET /__admin/conversionsInspect uploaded conversions, oldest first
GET /__admin/budgetsInspect campaign budgets
GET /__admin/budget-mutationsInspect the mutation audit trail: request ID, before and after per write
GET /__admin/request-metadataInspect redacted request metadata
POST /__admin/daily-metricsSeed synthetic daily Ads metrics (availableAt delays one row)
POST /__admin/page-tokens/expireExpire all current GAQL page tokens
GET /__admin/settingsRead reportingLagMs, pageTokenTtlMs, futureToleranceMs and searchPageSize
PUT /__admin/settingsUpdate those deterministic test settings
ToUse
Advance the reporting datePOST /__admin/clock {"advance": "1d"} or {"set": "<ISO-8601>"}; GAQL DURING ranges and Analytics today/yesterday/NdaysAgo follow it
Delay reportingPUT /__admin/settings {"reportingLagMs": n} hides new events until the clock passes it
Page a small fixturePUT /__admin/settings {"searchPageSize": n} (1 to 10,000)
Add latencythe slow_response preset, or POST /__admin/faults {"latencyMs": n, "count": 1}
Fail one requestthe server_error or network_reset preset
Throttlethe quota_exhausted or rate_limited preset; "count": n throttles n requests
See what arrivedGET /__admin/requests (the journal) and GET /__admin/request-metadata

Fault presets are quota_exhausted, rate_limited, server_error, network_reset, slow_response, ambiguous_budget_write, partial_budget_failure, and partial_conversion_failure. Each fires once unless count says otherwise, and is scoped to the calling namespace. The two throttling presets answer 429 RESOURCE_EXHAUSTED with quotaError: RESOURCE_EXHAUSTED or RESOURCE_TEMPORARILY_EXHAUSTED and the backoff in details.quotaErrorDetails.retryDelay, before anything is written.

ambiguous_budget_write commits the next executed budget mutation and then returns 503, so retry logic can be tested against an uncertain outcome. A validate-only preflight executes nothing and does not spend it: the fault waits for the real call that follows. Reconcile before replaying: the 503 carries a request-id header, and GET /__admin/budget-mutations lists the write under that request ID with the budget's before and after.

Sensitive event and conversion payloads are sealed in state; journals and inspection metadata contain only the fields needed for assertions.

API

The portable root exports GoogleAdsAPI, createRuntime, document, supportedOperationIds, GOOGLE_ADS_NAMESPACE, GOOGLE_ADS_PRESETS, DEFAULT_ADMIN_KEY, DEFAULT_TOKEN, DEFAULT_CUSTOMER, DEFAULT_CUSTOMERS, DEFAULT_BUDGETS, DEFAULT_CAMPAIGNS, DEFAULT_ACTIONS, DEFAULT_PROPERTY, DEFAULT_MEASUREMENT, DEFAULT_API_SECRET, createVaultKey, fingerprint, and the public fixture/runtime option types. The Node ./server entry exports createServer, DEFAULT_PORT, and server types. mockingbird-google-ads serve starts a listener.

Verification and scope

Acceptance tests cover GAQL precision and paging, budget preflight and partial writes, conversion deduplication, GA4 event validation and reporting, OAuth scope/expiry behavior, encrypted state, namespaces, resets, fault recovery, and the unmodified google-auth-library 11.1.0 HTTP signing path. Runtime tests drive every control above over /__admin. Property tests exercise every parity-enabled operation and prove that a divergent transport is detected deterministically.

test/consumer.ts is a port of the raw-fetch traffic described in the original service request. It is not the requesting application's client, whose source is not in this repository, so no test here runs that client unmodified.

Deliberately not modelled

The emulator implements a bounded subset. It does not model the complete Google Ads resource graph, every GAQL function, GAQL field-compatibility rules between segments and metrics, every Analytics dimension or metric, real Google identity, production quota allocation, billing, dashboards, attribution processing, or undocumented backend behavior. Uploaded conversions do not feed metrics.conversions; seed those with daily metrics. Normal operation is local and does not contact Google; only the explicit parity command uses credentials supplied through .env.local or GitHub Actions secrets.

版本与发布记录

@crvouga/mockingbird-service-google-ads 共发布 23 个版本,首次发布于 2026/10/05;过去 12 个月发布了 23 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.12.0latest2026/11/11今天
1.11.92026/11/038 天前
1.11.82026/11/038 天前
1.11.72026/11/038 天前
1.11.62026/11/038 天前
1.11.52026/11/038 天前

关于 @crvouga/mockingbird-service-google-ads 的常见问题

@crvouga/mockingbird-service-google-ads 是什么?

Google Ads v25 and GA4 emulator: GAQL metrics, budget mutations, conversion uploads and analytics events/reports.

如何安装 @crvouga/mockingbird-service-google-ads?

在项目目录运行 npm install @crvouga/mockingbird-service-google-ads,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-google-ads,可以用 npx mockingbird-google-ads 直接运行。

@crvouga/mockingbird-service-google-ads 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@crvouga/mockingbird-service-google-ads 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@crvouga/mockingbird-service-google-ads 可以商用吗?

@crvouga/mockingbird-service-google-ads 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@crvouga/mockingbird-service-google-ads 的下载量有多少?

根据 npm 官方下载统计,@crvouga/mockingbird-service-google-ads 在 2026/10/11 – 2026/11/09 这 30 天内被下载 3,135 次,日均约 105 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@crvouga/mockingbird-service-google-ads 还在维护吗?

最新版本 1.12.0 发布于 2026/11/11(今天);至今共发布 23 个版本,其中过去 12 个月发布了 23 个;首次发布于 2026/10/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。