npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@twentylabs/gads

v0.3.2

Published

Scriptable CLI for the Google Ads API: profiles, GAQL queries, and validated changes.

Readme

gads

A scriptable CLI for the Google Ads API (REST, v25), with no runtime dependencies.

It does three jobs:

  • Profiles. Each Google Ads account is one profile, and any project can use any of them.
  • gads query. Runs GAQL and prints the rows as a table, CSV, JSON or JSONL, for scripts and reports.
  • gads apply. Changes the account from a JSON change file.
    • By default it only asks Google to validate the change against the live account (validateOnly), and nothing is written.
    • --yes writes the change, reads the account again, and saves the state before and after as evidence.

For conversational analysis, use Google's official read-only MCP server. gads mcp-credentials hands it this CLI's OAuth credentials, so you only log in once.

Setup (once per Google Cloud project)

Google sunset developer tokens on 2026-09-09. API access now belongs to the Google Cloud project that owns your OAuth client. You need neither a manager account nor the API Center.

  1. Cloud project: in https://console.cloud.google.com, create a project or reuse one.

    • Under APIs & Services → Library, enable Google Ads API.
    • The project must be on a paid billing account, or have no billing at all. Google rejects access applications from projects on the free trial.
  2. Access level: open https://console.cloud.google.com/google/ads-apis/overview.

    | Level | What it reaches | | --- | --- | | Test | Test accounts only. This is what a new project gets. | | Explorer | Production accounts, up to 2,880 operations a day. This is enough for one person's management work. Apply here; Google often grants it automatically. | | Basic | 15,000 operations a day. Needs brand verification. |

    If you call a real account with Test access, the API returns CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION.

  3. OAuth consent screen: use user type External and add yourself as a test user.

    • Then set the publishing status to "In production". While it is in "Testing", Google expires refresh tokens after 7 days.
    • An unverified app only shows a warning screen, which you can click through.
  4. OAuth client: under Credentials → Create credentials → OAuth client ID, choose Desktop app, then download the JSON file.

Install

Requires Node 20 or later. Published on npm as @twentylabs/gads.

npm install -g @twentylabs/gads@^0.3
gads version
  • @^0.3 installs the newest release in the 0.3.x line.
  • With nvm, global packages belong to one Node version, so reinstall after switching Node.
  • Before 0.3.1, gads was installed from git tags (git+ssh://…/gads.git#v0.3.0); uninstall that copy first (npm uninstall -g gads).

Versions and upgrading

Releases are npm versions of @twentylabs/gads, tagged vX.Y.Z in git, with notes in CHANGELOG.md and on the GitHub releases page. Below 1.0.0, a minor bump (0.3 → 0.4) may break change files or scripts; a patch never does.

npm install -g @twentylabs/gads@^0.3     # newest 0.3.x
npm install -g @twentylabs/[email protected]    # pin or roll back
npm ls -g @twentylabs/gads               # what is installed

Consumers declare what they need. A project that keeps change files puts the version range in each file, and its README says gads >= X.Y.Z:

{ "gads": ">=0.2.0", "title": "...", ... }

An older gads refuses that file instead of misreading it, and prints the exact install command: needs gads >=0.2.0; you have 0.1.0. Upgrade: npm install -g "@twentylabs/gads@>=0.2.0". "schemaVersion" (default 1) guards the file format itself.

Cutting a release (maintainers):

  1. In the release PR, bump package.json and add the ## [X.Y.Z] entry to CHANGELOG.md.
  2. Merge to main.
  3. Run scripts/release.sh X.Y.Z. It refuses unless main is clean and pushed, the version is above the last tag, the entry exists and the tests pass. It pushes the tag vX.Y.Z; the release workflow then publishes that version to npm with trusted publishing (no token).

Log in

gads auth login --profile my-app \
  --customer-id 123-456-7890 \
  --client-json ~/Downloads/client_secret_XXXX.json
  • A browser opens. Approve access with the Google user who can see the Ads account.
  • If that user reaches the account through a manager account, add --login-customer-id <manager ID>.
  • The first profile you create becomes the default. Pass --default to make any other profile the default.
gads auth status            # who you are, what you reach, the account currency and time zone
gads profiles               # list profiles
gads profiles use other     # change the default profile

Profiles live in ~/.config/gads/config.json, which only you can read.

Any profile field can also come from an environment variable instead:

  • GADS_CUSTOMER_ID
  • GADS_LOGIN_CUSTOMER_ID
  • GADS_CLIENT_ID
  • GADS_CLIENT_SECRET
  • GADS_REFRESH_TOKEN
  • GADS_PROFILE, to choose a profile
  • GADS_CONFIG, to use a different config file

Read

gads campaigns
gads query "SELECT campaign.name, metrics.cost_micros, metrics.conversions
            FROM campaign WHERE segments.date DURING LAST_7_DAYS" --format csv --out week.csv
gads query --file report.gaql --profile other
  • In a terminal the output defaults to a table; in a pipe or with --out it defaults to JSON.
  • Every *_micros column gets a readable money column next to it.
  • --format json returns Google's rows untouched.

Change

A change file is a list of googleAds:mutate operations, plus the context a reviewer needs:

{
  "gads": ">=0.2.0",
  "title": "Pause Android TH",
  "reason": "250-install test reached; CPA 3x VN",
  "customerId": "123-456-7890",
  "operations": [
    { "campaignOperation": {
        "update": { "resourceName": "customers/1234567890/campaigns/111", "status": "PAUSED" },
        "updateMask": "status" } }
  ],
  "verify": [
    "SELECT campaign.id, campaign.status FROM campaign WHERE campaign.id = 111"
  ]
}
gads apply pause-th.json          # dry run: shows the operations and current state, then Google validates
gads apply pause-th.json --yes    # writes, re-reads verify, saves pause-th.result.json

Ready-made templates are in examples/: pause, budget, target CPA, and swapping a country.

Safety rules, enforced before anything is sent

| Rule | Why | | --- | --- | | customerId must match the profile | A change written for one account cannot run against another. | | Every resource name must belong to that customer | Same reason. | | No REMOVED status, and no removing campaigns, budgets, ad groups or ads, unless allow.remove is set | Google never lets you undo a remove. | | Micros must be positive whole numbers, and in VND whole dong (multiples of 1,000,000) | Catches the most common budget typo. | | No updating a shared budget unless allow.sharedBudget is set | It would move money in every campaign that uses the budget. | | No change that leaves a campaign with zero positive locations | A campaign with no locations serves worldwide. | | Google validateOnly must pass before --yes writes anything | Google checks the change against the live account. | | All operations go in one atomic request (partialFailure: false) | Either every operation lands or none does. | | A write is never retried | A retried create can land twice. | | A change that already has a .result.json is refused without --force | Prevents applying the same change twice. | | --read-only or GADS_READ_ONLY=1 refuses every write; validation still runs | Lets you work on an account without any risk of changing it. |

Every apply run appends a line to ~/.config/gads/audit.jsonl with the mode, the file's SHA-256, the account and the outcome.

Official MCP server (read-only analysis)

gads mcp-credentials --profile my-app --out ~/.config/gads/adc-my-app.json

This writes the profile's OAuth credentials as an authorized_user file and prints the matching claude mcp add command.

  • Both tools use the same Cloud project, so they share its daily operation quota.
  • If the profile's refresh token expires, both stop working at once.

Exit codes

| Code | Meaning | | --- | --- | | 0 | OK | | 1 | Usage error or refusal | | 2 | The API returned an error | | 6 | Refused by read-only mode |

Development

pnpm test     # node --test; never calls Google

The API version is pinned in lib/api.js. v25 sunsets around August 2027.

The reference implementations studied (all Apache-2.0) were google-ads-open-cli, BeckerEnterprises/google-ads-api-cli, mcc-gaql-rs, icoolqin/google-ads-cli and Benmore-Studio/gads. Their designs were consulted; no code was copied.