Download the V2 Syntax Reference (.md)
Version 1.0, Last Updated: April 2026
Overview
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.
Core Concepts
- Segment: Output table of items matching the formula expression
- V2 Logic: The Domain Specific Language described here. Segment queries are written using V2 Logic
- Custom Property: Output column generated by a
letvariable definition (starting with$) - Variable: Named value defined using
let(must start with$sigil) - Dataset: Selected source data table (Campaigns, Ad Groups, Keywords & Targets, etc.)
- Workflow: Trigger and Action pair
- Template: Predefined Logic + optional Workflow. Each Template runs using V2 Logic and can be applied to datasets such as Keywords & Targets, Campaigns, or Search Terms.
Data Types
Number
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.
String
Text values in double quotes. String concatenation and manipulation are not supported. Each string must be a complete literal value.
campaign name contains "Brand"Array
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"]List
Predefined string values (enums) for properties like state or match type. Values in double quotes.
state = "enabled"
state contains any ["paused", "archived"]Timestamp
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"Time Period
Duration specification used only in time-based property parentheses or variable assignments.
clicks(30d)
let $period = 7d..14d;Date
Literal date values in YYYY-MM-DD format returned by certain properties. Cannot be used directly in timestamp arithmetic.
campaign start date = 2024-01-15Boolean
True/false result of comparisons and logical operators. The final formula must evaluate to Boolean.
clicks(7d) > 0 and orders(7d) > 0Time Period Formats
Xd, Relative
X days back from now, including the partial current day.
clicks(7d)YYYY-MM-DD..YYYY-MM-DD, Literal Range
Exact calendar dates, inclusive.
spend(2024-01-01..2024-01-31)Xd..Yd, Offset Relative
From 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 Present
From now back through X days ago.
clicks(..60d) // from now through 60 days agoXd.., Offset From Past
From X days ago through earliest available data.
spend(30d..) // from 30 days ago through earliest available datalifetime or .., Lifetime
Entire period of available data.
orders(lifetime) = 0Common Pitfalls
Nested case Depth Limit
Nesting 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.
Compound Conditions in case for let Assignments
Combining multiple conditions with and in a single case clause can cause load errors. Use nested case statements instead.
Metric Function Calls in Final Filter
Calling metric functions directly in the final filter can cause load errors. Pre-calculate into let variables as 0/1 flags.
Variable Usage in Offset Relative Time Periods
For Xd..Yd format, assign the complete range to a single variable. You cannot construct the range from separate variables.
Timestamp Arithmetic with Variables
Variables holding Time Periods must use the interval() function for arithmetic.
Custom Property Output
Variables assigned Time Period values appear as columns but rows show blank values.
Boolean Literals
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)
);Datasets
The selected dataset determines which properties are available and which entities will be analyzed.
campaigns
Campaign-level analysis and actions. Available properties: all performance metrics, budget, campaign identifiers, last budget change. Actions: Change Daily Budget, Set State.
ad-groups
Ad group-level analysis and actions. Available properties: all performance metrics, default bid, campaign/ad group identifiers. Actions: Change Default Bid, Set State.
keywords-targets
Keywords & 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.
keywords
Manual 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.
targets
Auto 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-ads
Individual product advertisements (ASINs) within ad groups. Available properties: all performance metrics, campaign/ad group identifiers. Actions: Set State.
search-terms
Search queries that triggered ads. Available properties: all performance metrics plus the negated property. The state property is not available. Actions: Create Negative Exact Match.
Primary Properties
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 only
Current bid for Keyword or Target
bid > 0.75budget (Number), campaigns only
Current 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 only
Most recent bid update timestamp
last bid change < now() - interval(7d)max bid (Number), All datasets except search terms
Maximum bid limit set on the entity. Aliases: max_bid, maxbid
max bid > 2.00min bid (Number), All datasets except search terms
Minimum bid limit set on the entity. Aliases: min_bid, minbid
min bid > 0.10last budget change (Timestamp), campaigns only
Most recent budget update timestamp
last budget change < now() - interval(30d)match type (List), keywords-targets only
Keyword 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 terms
Current 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 only
Whether an exact match negative keyword already exists for this search term. Values: true, false
negated = falsesearch term (String), search-terms only
The 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"]KDP-Specific Properties
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.00Secondary Properties
campaign 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 Click
Functions
let $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.
- Custom function declarations must appear at the very top of the segment, before all
let $variablestatements - Functions can reference
$variablesdeclared anywhere in the segment (forward references are supported) - Arguments must be literal time periods (
7d,30d, etc.), cannot pass a$variableas an argument - The same function can be called multiple times with different periods in one expression
// 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) > 1
Boolean Variables
let $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;
Operators
Math: + - * / %
% is percentage conversion (25% = 0.25), not modulo.
bid + 0.10
now() - interval(7d)
acos(30d) < 25%Logical: and or
and is evaluated before or.
clicks(30d) > 5 and state = “enabled”Comparison: = != > >= < <=
state = “enabled”
clicks(7d) != 10String: contains, does not contain, starts with, ends with
Case-insensitive comparisons.
campaign name contains “Brand”
ad group name ends with “-Exact”Array: contains all, contains any, does not contain any
For String properties vs Arrays, or List properties vs Arrays.
campaign name contains any [“test”, “archive”]
state contains any [“paused”, “archived”]Date: after, before
For Timestamp comparisons.
campaign start date after “14 days ago”
last bid change before now() - interval(2d)Syntax Notes
- Property Naming: Use exact names with spaces as defined (e.g.,
target acos,ad group name) - Case Sensitivity: Properties, functions, and operators are generally case-insensitive
- String Literals: Use double quotes
- Date Literals: Write without quotes (YYYY-MM-DD). Quoted values are treated as strings and will cause type errors.
- Variable Names: Must start with
$and use underscores for spaces (e.g.,$my_long_vardisplays as “My Long Var”) - Comments:
//for single line,/* /for blocks - Final Expression: Must evaluate to Boolean after all
letstatements - Time Period Comparison: Use non-overlapping ranges (
0d..13dand14d..27drather than14dand14d..28d) - Operator Precedence: Math (
,/before+,-), Logical (andbeforeor). Use parentheses for clarity. - Array Creation: User-defined arrays use square brackets with comma-separated strings
- Currency Symbol:
$symbols are ignored in numeric values - Percent Symbol:
%after a number divides by 100 (25% = 0.25), not a modulo operator - Variable Negation: Direct negation of variables (
-$variable) is not supported. Use-1 * $variableinstead. - Range Formats:
Xd..Ydcan only be used in metric function parentheses, not withinterval()or timestamp arithmetic.
Error Handling
- Division by Zero: Operations like X/0 return null. Null values will not match any comparisons and will be excluded from filters.
- NaN Comparison: All comparisons with NaN evaluate false except
!=(NaN != value is true, NaN != NaN is true) - Infinity Comparison: Works as expected mathematically (Infinity > 100 is true)
- Null Value Detection: Use
is_null()to explicitly check for null values - Parsing Error, Undeclared variable: Using an undefined variable name or misspelled property
- Parsing Error, Expected time period: Time-based property used without a (TimePeriod) specification
- Parsing Error, Unbalanced parenthesis: Mismatched parenthesis count
- Parsing Error, Incompatible types: Operation between incompatible data types
- Parsing Error, Unexpected end of input: Missing closing bracket or semicolon after let statement
- Parsing Error, Expected ’;’ after let: Missing semicolon after let statement
Workflow Actions
Change Bid, keywords-targets, keywords, targets
- Increase ($): Increases current bid by fixed dollar amount
- Increase (%): Increases by percentage (input as decimal: 0.07 for 7%)
- Set ($): Sets bid to specific dollar amount
- Decrease ($): Decreases by fixed dollar amount
- Decrease (%): Decreases by percentage (input as decimal: 0.07 for 7%)
- Set from variable: Uses Custom Property value for any above operations
Change Default Bid, ad-groups
Same operations as Change Bid, applies to Ad Group default bid setting.
Change Daily Budget, campaigns
Same operations as Change Bid, applies to Campaign daily budget.
Set State, campaigns, ad-groups, keywords-targets, product-ads
Sets entity state to: enabled, paused, archived
Create Negative Exact Match, search-terms
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).
Known Issues
- KI-003:
case()cannot return Timestamp values. Workaround: Useletstatements with boolean logic.