Automation
The automation language
The complete reference: entities, fields, time ranges, operators, functions, and actions.
Rules are written in a small, readable language built for Amazon Ads: loop over an entity, check conditions on its metrics, call actions. The editor has syntax highlighting, autocomplete, inline error checking, and a built-in reference; every run is recorded and revertible.
The basic shape
| Statement | Meaning |
|---|---|
FOR EACH entity [AS name] [IN range]: | Loop over an entity. Default window: LAST 30 DAYS. OVER/USING are accepted for IN. |
IF condition: / WHEN condition: | Run the indented body when true; bodies may nest. |
LET name = expression | Name a value or related entity. Top-level LETs are visible everywhere; a LET in a body is visible in that body and below. |
END | Close a FOR EACH block. |
# comment | Ignored to the end of the line (except inside quotes). |
Bodies are indented two spaces. Keywords, entities, fields, and functions are case-insensitive.
Entities you can loop over
Hop to related entities with a dot: keyword.campaign, searchTerm.adGroup, campaign.portfolio, campaign.placement. Related objects can be named: LET campaign = keyword.campaign.
Metrics & fields
Read any metric off an item over the loop's window (or an inline one):
Plus settings and identity per entity: bid, bidInherited, budget, state, name, matchType, keywordText, searchTerm, asin, adType, targetingType, biddingStrategy, portfolioName, adGroupCount, placement percentages (top_of_search, product_pages, rest_of_search), and recency fields days_since_bid_change / days_since_budget_change. Friendly aliases work everywhere (daily_budget, purchases, conversion_rate, tos, …) — the editor autocompletes them all.
Time ranges
The window after FOR EACH is optional and defaults to the last 30 settled days. Any metric read can carry its own inline window: keyword.clicks IN LAST 7 DAYS.
| Range | Means |
|---|---|
LAST 7 DAYS / LAST 30 DAYS / LAST 90 DAYS | The last N settled days (excludes the two newest, still-settling days — see attribution). |
YESTERDAY | The latest settled attribution day (currently two UTC days behind today). |
TODAY | The current UTC day from the latest sync — partial and unlagged. |
N DAYS AGO | One exact unlagged UTC day. |
LIFETIME | All stored history. |
FROM 8 DAYS AGO TO 35 DAYS AGO | An offset baseline window, unlagged. |
BEFORE 8 DAYS AGO | All history older than 8 days ago (new-vs-historical checks). |
FROM 2026-01-01 TO 2026-01-31 | Explicit start/end dates. |
Conditions & operators
| Kind | Syntax |
|---|---|
| Logic | AND, OR, NOT, parentheses (precedence: NOT, AND, OR) |
| Comparison | =/==/IS, !=/<>/IS NOT, <, <=, >, >= (text equality is case-insensitive) |
| Lists | IN, NOT IN — e.g. keyword.matchType IN ["EXACT", "PHRASE"] |
| Text | CONTAINS, NOT CONTAINS, CONTAINS ANY [list], STARTS WITH, ENDS WITH (case-insensitive) |
| Arithmetic | + - * / % (+ concatenates text; % is modulo), unary - |
| Units | money $0.85, percent 45% (= 0.45), plain numbers, TRUE/FALSE, NONE, ["lists"] |
| Inline window | expression IN range — e.g. keyword.acos IN LAST 7 DAYS > keyword.acos IN LAST 90 DAYS |
Historical setting reads: value-returning methods give you a setting as it was N days ago — keyword.historicalBid(30 DAYS) / target.historicalBid(…), campaign.historicalBudget(…), campaign.historicalBiddingStrategy(…), and campaign.historicalPlacementBid("TOP OF SEARCH", 30 DAYS). Each accepts 30 DAYS, 30 DAYS AGO, YESTERDAY, or a plain number of days, and is a value for conditions and LET, not a step — e.g. a drift check: IF keyword.bid > keyword.historicalBid(30 DAYS) * 1.5. Bids come from the daily targeting report, campaign settings from the change log; if history doesn't reach that far, the value is unknown and the comparison simply never matches.
Actions
| Action | On | What it does |
|---|---|---|
.pause() / .enable() / .setState("PAUSED") | campaign, adGroup, keyword, target, product | Pause or enable the item. |
.setBid(amount) | keyword, target | Set the bid — compute it, e.g. keyword.bid * 0.9. |
.setBudget(amount) | campaign | Set the daily budget. |
.setBiddingStrategy("FIXED BIDS") | campaign | Also "DYNAMIC BIDS - DOWN ONLY", "DYNAMIC BIDS - UP AND DOWN". |
.setPlacementBid("TOP OF SEARCH", 50) | campaign | Placement adjustment 0–900%; also "PRODUCT PAGES", "REST OF SEARCH". |
.setName(text) / .rename(text) | campaign | Rename the campaign. |
.moveToPortfolio(PORTFOLIO("Brand A")) | campaign | Move to a portfolio (setPortfolio is an alias). |
.addNegative(text[, "exact"|"phrase"]) | campaign, adGroup, keyword, target, searchTerm, product | Add a negative keyword; match type defaults to exact. See negation. |
.createKeyword(text[, match[, bid]]) | adGroup, keyword, target, searchTerm, product | Create a positive keyword in the entity's ad group — the harvesting primitive. Match: exact/phrase/broad (default exact). |
.note("…") | any | The reason logged with every action in the same body. Placeholders: {clicks}, {acos:percent}, {spend:money}, {field:number}, {campaign_name}, {ad_group_name}, and any scalar LET variable. |
Functions
| Function | What it does |
|---|---|
MIN(…) / MAX(…) / CLAMP(v, lo, hi) | Smallest / largest / keep a number inside limits — the usual bid-guard tools. |
ROUND(v[, places]), FLOOR(v), CEIL(v), ABS(v) | Numeric shaping. |
IF(cond, then, else) | Choose a value; chain IF(c1, v1, c2, v2, …, default) for multi-branch logic. |
METRIC("clicks", "last7") | Read a metric for the current item in another window ("last7", "today", "8..35", "8.."). |
LAST_CHANGE("bid") / DAYS_SINCE_CHANGE("budget") | When the latest applied bid/budget change happened — for cool-downs between adjustments. |
PORTFOLIO("name") | Find a portfolio by exact (case-insensitive) name. |
LOWER, UPPER, LENGTH, REPLACE, CONCAT, TODAY() | Text and date helpers. |