Guide to targeting with JEXL
For a more in-depth explanation of JEXL syntax you can read the Normady project docs.
How to write JEXL targeting expressions
A message needs to contain the targeting property (JEXL string) which is evaluated against the provided attributes.
Examples:
{
"id": "7864",
"content": {...},
// simple equality check
"targeting": "usesFirefoxSync == true"
}
{
"id": "7865",
"content": {...},
// using JEXL transforms and combining two attributes
"targeting": "usesFirefoxSync == true && profileAgeCreated > '2018-01-07' | date"
}
{
"id": "7866",
"content": {...},
// targeting addon information
"targeting": "addonsInfo.addons['activity-stream@mozilla.org'].name == 'Activity Stream'"
}
{
"id": "7866",
"content": {...},
// targeting based on time
"targeting": "currentDate > '2018-08-08' | date"
}
Available JEXL transforms and operators
Firefox extends standard JEXL with additional transforms and a binary operator, defined in FilterExpressions.sys.mjs. Transforms are applied using the pipe operator (|), e.g. someValue | transformName.
date
Converts a date string into a Date object.
currentDate | date > "2025-05-06" | date
stableSample
Hashes the input and returns true if the hash falls below the given rate (0.0–1.0).
// Target approximately 10% of users, consistently
clientID | stableSample(0.1)
bucketSample
Hashes the input and returns true if it falls within the given bucket range (start to start + count) out of total buckets. The range wraps around if it exceeds total, so bucketSample(70, 50, 100) checks buckets 70–99 and 0–19.
// Target 500 out of 10,000 buckets
userId | bucketSample(0, 500, 10000)
preferenceValue
Returns the current value of a Firefox preference. Supports string, integer, and boolean preference types. Returns defaultValue if the preference does not exist, and throws if the preference exists but is of an unrecognised type.
"browser.newtabpage.enabled" | preferenceValue
"some.pref" | preferenceValue(true)
preferenceIsUserSet
Returns true if the user has explicitly changed the preference from its default value. A preference reset to its default value is considered not user-set, even if the current value matches what the user previously set.
"browser.newtabpage.enabled" | preferenceIsUserSet
preferenceExists
Returns true if the preference exists with any valid type (string, integer, or boolean). Returns false for preferences with an invalid or unrecognised type.
"some.optional.pref" | preferenceExists
keys
Returns an array of the enumerable keys of an object, or undefined if the input is not an object.
providerCohorts | keys
length
Returns the length of an array, or undefined if the input is not an array.
topFrecentSites | length > 5
mapToProperty
Given an array of objects, returns a new array of a single named property extracted from each element.
topFrecentSites | mapToProperty("host")
intersect
Returns the elements present in both arrays, or undefined if either argument is not an array. Unlike the transforms above, this is used as an infix operator rather than with a pipe.
topFrecentSites | mapToProperty("host") intersect ["amazon.com", "ebay.com", "etsy.com"]
regExpMatch
Matches a string against a regular expression. Returns an array of matches, or null if there are none. Accepts an optional flags argument.
currentURL | regExpMatch("^https://example\\.com/")
currentURL | regExpMatch("^https://example\\.com/", "i")
versionCompare
Compares two version strings. Returns 0 if equal, a negative number if the left is lower, or a positive number if the left is higher.
version | versionCompare("120.0") >= 0