Keyword .forecast
Price a paid test before any ad account spends: the clicks, impressions and spend your terms would get next month at your bid.
- Price
- 9¢ a forecast
- Success rate
- 100% of 97 calls
- Freshness
- Fresh for 7 days
- Emits
Keyword.forecasted- Capability
- Market data
POST https: //api.sb/ {your-domain}/ keywords/ forecast
Inputs
| Name | Type | Default | Meaning |
|---|---|---|---|
keywords | string[] | Required | Up to 1,000 terms, priced as one set. |
bid | number | Required | Your most per click, in USD. Start at your break-even cost per click, never above it. |
match | 'exact' | 'phrase' | 'broad' | 'exact' | Run a first test on exact match only; broad match spends on terms you did not choose. |
venue | 'google-search' | 'bing' | 'google-search' | The search site to forecast. |
locale | string | your home Market | The market and language, such as en-US. |
period | 'next-month' | 'next-month' | The window the forecast covers. |
maxCost | number | 0.20 | The most this call may spend, in USD. Over it, the call is refused before it spends, or stops early with what it has. |
Outputs
| Field | Type | Unit | What null means |
|---|---|---|---|
clicks | number | null | clicks in period | Too little volume to forecast, never zero clicks. |
impressions | number | null | impressions in period | Too little volume to forecast. |
ctr | number | null | share, 0.042 is 4.2% | Too little volume to forecast. |
averageCpc | number | null | USD a click | Too little volume to forecast. |
spend | number | null | USD in period | Too little volume to forecast. |
perKeyword | { term: | None. | Never null: one row per term; null where a term alone is too thin to forecast. |
keywords | string[] | None. | Never null: the set forecast. |
bid | number | USD | Never null. |
match | 'exact' | 'phrase' | 'broad' | None. | Never null. |
period | string | None. | Never null. |
(row) | Observed | None. | The forecast carries observedAt, method, venue and locale; method is reported from your own ad account. |
cost | Cost | USD | Never null. In try mode usd is 0 and maxUsd is what the call would have cost. |
Read the result
| Field | Value | What it means | What to do |
|---|---|---|---|
averageCpc | Over $4.29 for a $149 a month product | Every click costs more than a customer it might become is worth in a year. | Earn these terms with pages, or test only with a price above $300 a month. (break-even cost per click, the strategy numbers) |
clicks | Under 500 for the month | A paid test is read at 500 clicks; fewer cannot tell 1% from 3% signups apart. | Add exact terms until a month reaches 500 clicks, or plan a two-month test and budget it. (the 500-click reading rule) |
spend | Over the budget you set | The bid buys more clicks than you can afford to read. | Lower the bid toward break-even, or cut the terms with the highest perKeyword spend. (the stop, hold or scale rule) |
ctr | Under 3% on exact match | Forecast click rates assume an ad that echoes the term. | Put the term in headline 1 of every ad you test. (industry averages: 6.66% click rate across 16,000 advertisers) |
Effects
- Action class
None: it reads, so no approval rule names it
- Modes
try: Runs the read and returns real rows; nothing is saved and nothing is billed.send: Returns a pending Action at once; its Event carries the rows when the read finishes.do: Waits for the read and returns the rows, billed per result.
- Idempotency
The same
Idempotency-Keywith the same input replays the first answer at $0; with other input it returns 409.- Saved or shared
Nothing is written to your records, and no ad account spends. Forecasts are shared across startups for the same terms, bid and match for 7 days.
- Emits
Keyword.forecastedwith{ keywords,bid, match, clicks, impressions, spend } - Performed by
- Price
About 9¢ a forecast. Free: a forecast from your own Google Ads account.
maxCostdefaults to 20¢. One forecast for each of 3 bids on the same 40 terms: 3 × 9¢ a forecast is about 27¢.- Reliability
The first route succeeds 100% of 97 calls. If it fails, the call refuses with
sources-busyand nothing is spent.- Freshness
A reading younger than 7 days returns at $0. Readings are shared across startups for the same subject and locale.
- Batch and pages
Up to 1,000 terms a forecast. It answers in one response.
- Rate
The shared rate rules: 10 calls a second per key, and an array input counts as one call.
Refuses when
| Check | Error | Fix | Then call |
|---|---|---|---|
A search engine, answer engine or network the call does not read, such as ChatGPT sent to Keyword.measure | venue-unsupported | Pick one the call’s venue input lists; AI answers are Keyword.ask, posts are Keyword.search. | Keyword.ask |
Every data call can also meet the shared data-call refusals: filter-unsupported, input-missing, limit-exceeded, max-cost, rate-limited, sources-busy.
The venue-unsupported payload
{
"type": "https://startupbuilder.dev/errors/venue-unsupported" ,
"title": "The call does not read that search engine or network",
"status": 422,
"detail": "A search engine, answer engine or network the call does not read, such as ChatGPT sent to `Keyword.measure`." ,
"fix": "Pick one the call’s `venue` input lists; AI answers are `Keyword.ask`, posts are `Keyword.search`." ,
"next": {
"verb": "Keyword.ask",
"input": {
"keyword": "best rent tracking software for a 40-unit property manager",
"venues": [
"chatgpt"
]
}
},
"instance": "https://api.sb/leaseline.app/actions/action_1"
}When it waits
Returns in one response; nothing waits.
Example
What would a month of exact-match ads on two rent-tracking terms cost at
a $12 bid? Spend up to 10¢. To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.
Test values
A sk_test_ key answers these the same way every time, at $0 (every test value).
| Test value | Always returns | What it is for |
|---|---|---|
maxCost: | Refuses with max-cost | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
rate-limited.test | Refuses with rate-limited | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
sources-busy.test | Refuses with sources-busy | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |
Used by
- Workflows: Ad test setup
- Jobs: Run ads