Skip to content

Google Ads

Your agents forecast your terms, build exact-match search campaigns on your Google Ads account, cut wasted search terms daily, and stop by your rule.

Connect
Sign in once, 1 grant
Runs through
Your account
First run
Forecast clicks and cost for 10 exact terms, about 90¢
Metric.query
You, to your agent

Which search terms spent over $20 last week with no signup? Show me what to add as negatives.

curl -X POST "https://api.sb/leaseline.app/metrics/query?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"metric":"ad-spend","shape":"trend","breakdown":"search-term","window":"7d","where":"signups = 0 and spend > 20"}'
npx startup-builder do Metric.query --try --data '{"metric":"ad-spend","shape":"trend","breakdown":"search-term","window":"7d","where":"signups = 0 and spend > 20"}'
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Metric.query({ metric: 'ad-spend', shape: 'trend', breakdown: 'search-term', window: '7d', where: 'signups = 0 and spend > 20' })"
  }
}
import { $ } from 'startup-builder'

const result = await $.try.Metric.query({ metric: 'ad-spend', shape: 'trend', breakdown: 'search-term', window: '7d', where: 'signups = 0 and spend > 20' })
Response
{
  "$type": "Metric",
  "mode": "try",
  "stored": false,
  "metric": "ad-spend",
  "window": "7d",
  "rows": [
    {
      "searchTerm": "free rent receipt template",
      "spend": 64.2,
      "clicks": 31,
      "signups": 0,
      "action": "add as a negative"
    },
    {
      "searchTerm": "property management software enterprise",
      "spend": 48.9,
      "clicks": 9,
      "signups": 0,
      "action": "add as a negative"
    }
  ]
}
Try mode reads, stores nothing and spends nothingAPI referenceIts Nouns

Connect once

  1. Call Integration.connect with system: 'ads' and venue: 'google-search', then open the connectUrl it returns and sign in as a Google account with access to your Google Ads account.
  2. Pick the Google Ads account, then link it to your Google Analytics property so signups count as conversions.
  3. Set the spend on your standing approval with Mandate.authorize; Google bills your account, never the platform.
GrantWhat it unlocksScope
Manage your Google Ads accountReports, campaigns, ad groups, keywords, ads, budgets and audiences; Google offers no read-only grant, so your standing approval holds what changeshttps://www.googleapis.com/auth/adwords
ToDo this
PauseIntegration.pause stops every call through Google at once and keeps the token; Integration.resume picks up from the same cursor.
ReconnectIntegration.reconnect returns a fresh connectUrl that lasts one hour, and keeps the Integration's id and cursor, so nothing imports twice.
DisconnectIntegration.revoke revokes the token with Google; every record it brought in stays in your records.

What your agents do

AskVerbRuns throughPrice
Build the search campaign: 4 ad groups of exact terms, two ads each, and my negatives.Campaign.createYour accountFree
Add an ad to the best ad group with the winning headline.Ad.createYour accountFree
Add the search terms that wasted money as negatives, and lower the budget to $30 a day.Campaign.updateYour accountFree
Which search terms spent over $20 last week with no signup?Metric.queryYour accountFree
Build a remarketing list from pricing-page visitors.Audience.createYour accountFree

Calls on your own account are free; Google bills your spend directly.

Reading this site’s public data needs no account: Keyword.forecast, Ad.find are Data calls (the three ways a call runs).

What it holds

NounThe account’s objectWhenWhich side leads
Campaigncampaign and campaign_budgetYour agent builds itYour records
Adad_group_adYour agent builds it; Google’s review sets its statusYour records
Keywordsearch_term_viewA search triggers your adThe account
Audienceuser_listYour agent builds oneYour records
Entrymetrics.cost_microsEach day’s spend settlesThe account

Events and webhooks

DirectionEvent
EmitsCampaign.created, Campaign.updated, Ad.created, Audience.created, Keyword.measured, Entry.posted

Any Event can wake a Workflow, and a Watch delivers it to your endpoint, signed (Events and webhooks).

Limits

WhatLimitCall
A day’s spendGoogle may spend up to twice the daily budget on one day and holds the month to about 30.4 days of it, so your standing approval’s cap is set on the monthCampaign.update
Ad reviewGoogle reviews every ad; a disapproval comes back as venue-rejected with the policy it namesAd.create
Smart BiddingLearns from your conversion volume, and a new account has none, so a first test runs on manual CPC or maximize clicks on exact termsCampaign.create
SpendYour standing approval holds the cap; a budget change past it waits with over-mandateCampaign.update

Start here

MoveThe rule
StructureOne search campaign, 3 to 5 ad groups of tightly themed exact terms, two responsive search ads per group, and the negatives in place on day 0.
BudgetSpend what 500 clicks cost at your terms’ cost per click, on manual CPC or maximize clicks, and only on terms whose cost per click sits under your break-even.
CreativeThe search term in headline 1, the outcome in headline 2, and a landing page whose H1 repeats the term with one call to action.
Kill ruleAt 500 clicks: stop if cost per signup at the interval’s upper bound still fails break-even, hold and rewrite for 300 more if only the lower bound fails, and scale one tier only when the lower bound passes.
BenchmarkSource
CTR 6.66%, cost per click $5.26, conversion 7.52%, cost per lead $70.11Study of 16,000+ advertisers, 2025
Judge a bidding change over 2 conversion cycles or 2 weeks, whichever is longerGoogle Ads help
10 signups in 500 clicks reads as 2%, with an interval of 1.1% to 3.6%Our calculation (Wilson interval)
No signup in 150 clicks stops the test: a 2% rate would show one 95% of the timeOur calculation

Field map

Our fieldGoogle Ads’s fieldNotesCalls
Campaign.objectivecampaign.advertising_channel_typeWith a conversion goal; leads runs a SEARCH campaign bidding toward your signup conversionCampaign.create, Campaign.update, Ad.create
Campaign.budgetcampaign_budget.amount_microsA daily amount in millionths: $40 is 40000000Campaign.create, Campaign.update, Ad.create
Campaign.startsAtcampaign.start_dateNone.Campaign.create
Campaign.endsAtcampaign.end_dateNone.Campaign.create
Campaign.keywordsad_group_criterion.keywordmatch_type EXACT for a testCampaign.create, Campaign.update
Campaign.negativescampaign_criterion.negativeWith the wasted search term as its keywordCampaign.create, Campaign.update
Ad.headlinead_group_ad.​ad.​responsive_search_ad.​headlines3 to 15, each 30 charactersAd.create
Ad.bodyad_group_ad.​ad.​responsive_search_ad.​descriptions2 to 4, each 90 charactersAd.create
Ad.landingUrlad_group_ad.ad.final_urlsNone.Ad.create

What try does here

Sends every change with validate_only set: Google Ads checks the whole build and returns any error, and creates nothing.

How long a connection lasts

A connection lasts until you revoke it in your Google Account; Google also ends a grant left unused for six months, and every call your agents make counts as use.

The platform asks you to reconnect 7 days before it runs out; until you do, a call that needs it refuses with needs-reauth.

Formats

SiteFormatSizeLimits
Google SearchResponsive search adNone.3 to 15 headlines of 30 characters; 2 to 4 descriptions of 90; two paths of 15
YouTubeVideoNone.Title 100 characters; description 5,000 bytes; tags 500 characters in all

Plays and strategies

Used by

Reference

5 calls, each with its path and price
CallPathPrice
Campaign.createPOST /campaigns/createFree
Ad.createPOST /ads/createFree
Campaign.updatePOST /campaigns/updateFree
Metric.queryPOST /metrics/queryFree
Audience.createPOST /audiences/createFree

Contents