Features
Version 1.0 — Last Updated: April 2026
Merch Jar V2 Logic is a Domain Specific Language (DSL) for creating Segments of advertising entities by defining filter logic and calculating Custom Properties. Segments can be used for analysis, bulk actions, or automated Workflows.
let variable definition (starting with $)let (must start with $ sigil)Numeric values (integers, decimals). Percentages (%) auto-convert to decimal (25% becomes 0.25). Literal negative numbers supported.
clicks(7d) > 10
bid <= 1.50
acos(30d) < 25%
let $threshold = -0.5;Percentages are automatically converted — do not manually divide by 100.
To negate a variable value, use multiplication:-1 * $bid_adjustment. Direct negation (-$bid_adjustment) is not supported.
Text values in double quotes. String concatenation and manipulation are not supported. Each string must be a complete literal value.
campaign name contains "Brand"User-defined collection of strings using square brackets. Used with contains all and contains any.
let $keywords = ["retro", "vintage"];
campaign name contains any ["summer", "spring"]Predefined string values (enums) for properties like state or match type. Values in double quotes.
state = "enabled"
state contains any ["paused", "archived"]Point in time, stored as seconds since Unix epoch. Used with properties like last bid change and now() results.
last bid change < now() - interval(7d)
campaign start date after "60 days ago"Duration specification used only in time-based property parentheses or variable assignments.
clicks(30d)
let $period = 7d..14d;Literal date values in YYYY-MM-DD format returned by certain properties. Cannot be used directly in timestamp arithmetic.
campaign start date = 2024-01-15True/false result of comparisons and logical operators. The final formula must evaluate to Boolean.
clicks(7d) > 0 and orders(7d) > 0Xd — RelativeX days back from now, including the partial current day.
clicks(7d)YYYY-MM-DD..YYYY-MM-DD — Literal RangeExact calendar dates, inclusive.
spend(2024-01-01..2024-01-31)Xd..Yd — Offset RelativeFrom X days ago to Y days ago, inclusive (Y must be greater than or equal to X).
sales(7d..14d) // from 7 days ago through 14 days ago
sales(3d..3d) // 3 days ago only..Xd — Offset To PresentFrom now back through X days ago.
clicks(..60d) // from now through 60 days agoXd.. — Offset From PastFrom X days ago through earliest available data.
spend(30d..) // from 30 days ago through earliest available datalifetime or .. — LifetimeEntire period of available data.
orders(lifetime) = 0Nesting case statements more than 2–3 levels deep causes significant query performance degradation. Each case arm generates a conditional check evaluated against every row; deep nesting multiplies this across potentially millions of records. Limit nesting to 2 levels maximum.
Combining multiple conditions with and in a single case clause can cause load errors. Use nested case statements instead.
Calling metric functions directly in the final filter can cause load errors. Pre-calculate into let variables as 0/1 flags.
For Xd..Yd format, assign the complete range to a single variable. You cannot construct the range from separate variables.
Variables holding Time Periods must use the interval() function for arithmetic.
Variables assigned Time Period values appear as columns but rows show blank values.
Direct true/false literals are not supported. Use expression results instead.
// This will cause parsing errors:
let $period = case(condition => 7d, else 14d);// Use this approach instead:
let $grace_cutoff = case(
condition => now() - interval(7d),
else now() - interval(14d)
);The selected dataset determines which properties are available and which entities will be analyzed.
campaignsCampaign-level analysis and actions. Available properties: all performance metrics, budget, campaign identifiers, last budget change. Actions: Change Daily Budget, Set State.
ad-groupsAd group-level analysis and actions. Available properties: all performance metrics, default bid, campaign/ad group identifiers. Actions: Change Default Bid, Set State.
keywords-targetsKeywords & Targets combined — recommended for most use cases. Available properties: all performance metrics, bid, match type, last bid change, campaign/ad group identifiers. Actions: Change Bid, Set State.
keywordsManual keywords only (broad, phrase, exact match types). Available properties: all performance metrics, bid, match type, last bid change, campaign/ad group identifiers. Actions: Change Bid, Set State.
targetsAuto targeting and product targeting only (close match, loose match, product exact, similar, etc.). Available properties: all performance metrics, bid, match type, last bid change, campaign/ad group identifiers. Actions: Change Bid, Set State.
product-adsIndividual product advertisements (ASINs) within ad groups. Available properties: all performance metrics, campaign/ad group identifiers. Actions: Set State.
search-termsSearch queries that triggered ads. Available properties: all performance metrics plus the negated property. The state property is not available. Actions: Create Negative Exact Match.
acos (Number, Time-Based)Advertising Cost of Sale (spend / sales)
acos(30d) > 40%ad group name (String)Current name of the Ad Group
ad group name contains "Exact Match"aov (Number, Time-Based)Average Order Value (sales / orders)
aov(60d) > 15.00bid (Number) — keywords-targets onlyCurrent bid for Keyword or Target
bid > 0.75budget (Number) — campaigns onlyCurrent daily budget for Campaign. Alias: daily budget
budget > 10.00campaign name (String)Current name of the Campaign
campaign name contains "Brand - SP"campaign start date (Date)Configured start date of Campaign in literal format. Returns YYYY-MM-DD — cannot be used with now() arithmetic.
campaign start date = '2024-01-01'clicks (Number, Time-Based)Total number of ad clicks
clicks(7d) >= 5cpc (Number, Time-Based)Cost Per Click (spend / clicks)
cpc(14d) < 0.80impressions (Number, Time-Based)Total number of ad displays
impressions(14d) > 1000last bid change (Timestamp) — keywords-targets onlyMost recent bid update timestamp
last bid change < now() - interval(7d)max bid (Number) — All datasets except search termsMaximum bid limit set on the entity. Aliases: max_bid, maxbid
max bid > 2.00min bid (Number) — All datasets except search termsMinimum bid limit set on the entity. Aliases: min_bid, minbid
min bid > 0.10last budget change (Timestamp) — campaigns onlyMost recent budget update timestamp
last budget change < now() - interval(30d)match type (List) — keywords-targets onlyKeyword match type or auto-targeting type. Values: "broad", "phrase", "exact", "product exact", "similar", "close match", "loose match", "complements", "substitutes"
match type = "exact"orders (Number, Time-Based)Total orders directly attributed to ads
orders(30d) > 1roas (Number, Time-Based)Return on Ad Spend (sales / spend)
roas(30d) > 3.0sales (Number, Time-Based)Total revenue from attributed orders
sales(14d) > 50.00spend (Number, Time-Based)Total ad spend
spend(30d) > 100state (List) — All datasets except search termsCurrent status of entity. Values: "effectively enabled", "enabled", "paused", "archived"
state = "effectively enabled"target acos (Number)Desired ACOS percentage goal
target acos < 30%negated (List) — search-terms onlyWhether an exact match negative keyword already exists for this search term. Values: true, false
negated = falsesearch term (String) — search-terms onlyThe actual search query text that triggered the ad
search term contains "running shoes"
search term contains any ["brand name", "product category"]
search term does not contain any ["competitor", "irrelevant term"]blended acos (Number, Time-Based)Blended ACOS (spend / blended profit)
blended acos(60d) < 35%blended profit (Number, Time-Based)Total estimated profit combining sales and KENP royalties
blended profit(30d) > 50.00blended roas (Number, Time-Based)Blended Return on Ad Spend (blended profit / spend)
blended roas(30d) > 2.0pages read (Number, Time-Based)KENP pages read attributed to ads
pages read(60d) > 2000estimated royalties (Number, Time-Based)Estimated royalties from KENP pages read
estimated royalties(30d) > 10.00campaign end date (Timestamp) — Configured end date of Campaigndefault bid (Number) — Default bid set at Ad Group levelroi (Number, Time-Based) — Return on Investment ((sales - spend) / spend)cac (Number, Time-Based) — Customer Acquisition Cost (spend / orders)adjusted orders (Number, Time-Based, KDP) — Orders adjusted by Order Impact Multiplieradjusted sales (Number, Time-Based, KDP) — Sales adjusted by Order Impact Multiplieradjusted page reads (Number, Time-Based, KDP) — KENP pages adjusted by KENP Impact Multiplieradjusted estimated royalties (Number, Time-Based, KDP) — Royalties adjusted by KENP Impact Multiplierblended aov (Number, Time-Based, KDP) — Blended Average Order Valueblended cac (Number, Time-Based, KDP) — Blended Customer Acquisition Costblended cvr (Number, Time-Based, KDP) — Blended Conversion Rateblended rpc (Number, Time-Based, KDP) — Blended Revenue Per Clicklet $variable_name = expression;Defines a named variable with $ sigil. Creates a Custom Property column. Must end with semicolon. Variable names must be one word after $ (use underscores for spaces) and cannot conflict with keywords, properties, functions, or operators.
let $target_rpc = 0.75;
let $current_rpc = sales(30d) / clicks(30d);
let $period = 7d..14d;
let $unprofitable_acos_ratio = $chosen_acos / target_acos;now()Returns the current timestamp.
last bid change < now() - interval(14d)interval(time_period)Converts a Time Period to an internal duration for timestamp arithmetic. Cannot accept calculated values.
last bid change < now() - interval(7d)
// Convert a single duration to seconds
let $week_seconds = interval(7d);
// Subtract two durations to find span between
let $baseline_seconds = interval(30d) - interval(7d);
let $baseline_days = $baseline_seconds / 86400;
// Example use in logic
let $baseline_avg = impressions(7d..30d) / $baseline_days;case(condition1 => value1, condition2 => value2, ..., else defaultValue)Implements if/then/else logic. All return values must be the same data type. else is required. Cannot accept Time Period values.
let $performance = case(acos(14d) < 25% => "Good", acos(14d) < 40% => "Okay", else "Poor");Limit nesting to 2 levels deep maximum. Deeper nesting causes significant query performance issues at scale. Maximum of 10 match arms per case statement recommended.
is_null(property)Returns true if a property value is null, false otherwise. Commonly used with timestamp properties.
is_null(last bid change) // True if never changed
is_null(last bid change) = true // Explicit version
is_null(last bid change) = false // Has been changed
is_null(last budget change) = true // Never changed budgetlet function_name(param) = expression;Defines a reusable custom function that accepts a time period parameter. Useful for applying the same calculation across multiple time periods without repeating logic.
let $variable statements$variables declared anywhere in the segment (forward references are supported)7d, 30d, etc.) — cannot pass a $variable as an argument// Declare before any $variable declarations
let rpc(x) = sales(x) / clicks(x);
// Call with different periods for trend comparison
rpc(7d) > rpc(30d)
// Use in case logic
let $trend = case(rpc(7d) > rpc(30d) => "improving", else "declining");
// Functions can reference $variables declared later in the segment
let efficiency(x) = clicks(x) / $target_clicks;
let $target_clicks = 20;
efficiency(30d) > 1let $variable = comparison_expression;Boolean comparison results can be assigned directly to variables and used throughout segment logic.
let $x = spend(30d) > 10;
let $y = clicks(30d) > 5;
// Use in final filter
acos(30d) > 20% and $x
// Combine boolean variables
let $both = $x and $y;
$both
// Use in case statements
let $result = case($x => "qualified", else "not qualified");
// Check explicit boolean state
let $not_x = $x = false;+ - * / %% is percentage conversion (25% = 0.25), not modulo.
bid + 0.10
now() - interval(7d)
acos(30d) < 25%and orand is evaluated before or.
clicks(30d) > 5 and state = "enabled"= != > >= < <=state = "enabled"
clicks(7d) != 10contains, does not contain, starts with, ends withCase-insensitive comparisons.
campaign name contains "Brand"
ad group name ends with "-Exact"contains all, contains any, does not contain anyFor String properties vs Arrays, or List properties vs Arrays.
campaign name contains any ["test", "archive"]
state contains any ["paused", "archived"]after, beforeFor Timestamp comparisons.
campaign start date after "14 days ago"
last bid change before now() - interval(2d)target acos, ad group name)$ and use underscores for spaces (e.g., $my_long_var displays as "My Long Var")// for single line, /* */ for blockslet statements0d..13d and 14d..27d rather than 14d and 14d..28d)*, / before +, -), Logical (and before or). Use parentheses for clarity.$ symbols are ignored in numeric values% after a number divides by 100 (25% = 0.25) — not a modulo operator-$variable) is not supported. Use -1 * $variable instead.Xd..Yd can only be used in metric function parentheses, not with interval() or timestamp arithmetic.!= (NaN != value is true, NaN != NaN is true)is_null() to explicitly check for null valuesSame operations as Change Bid, applies to Ad Group default bid setting.
Same operations as Change Bid, applies to Campaign daily budget.
Sets entity state to: enabled, paused, archived
Creates a negative exact match keyword in the same ad group where the search term was found.
Action Rounding: Bid/budget calculations with sub-cent values are rounded using the account rounding strategy (default: Weighted Rounding).
case() cannot return Timestamp values. Workaround: Use let statements with boolean logic.© Merch Jar LLC