revenuecat-audiences
Use before sharing a link to a filtered customer list or audience, and when identifying, filtering, or ranking the user's customers (a segment, who they are, a product or duration, spend, renewals, status, country, attribution).
How do I install this agent skill?
npx skills add https://github.com/revenuecat/ai-toolkit --skill revenuecat-audiencesIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides instructions for managing RevenueCat customer segments and dashboard links. No malicious behavior or security vulnerabilities were identified.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Audience filters and dashboard links
Use Audiences to filter the user's customers and to share a dashboard link to that set. Filters
select the segment; sort_by / sort_direction on preview-audience order the returned sample.
There is no first-class CLI command for audiences. Do not tell the user RevenueCat cannot filter or segment customers.
Identifying, filtering, or ranking customers
Audiences filter on the fields below, including:
- Product and duration —
latestProduct,allPurchasedProductIds,latestPurchasedOffering, entitlements, offers - Spend and renewals —
totalSpent(filter, andsort_by: total_spent),totalRenewals(filter only; there is no renewal sort) - Subscription state —
status, trial, auto-renew intent, ownership - Store, platform, and country —
platform,latestStore,country,storefront - Dates — first seen, purchases, renewals, expiration, trial, cancellation
- Attribution and experiments — media source, campaign, ad group, keywords, price experiment
- Identity and custom attributes — app user ID, email, locale,
customAttribute:{key}
Map the question onto those fields, filter, then read a sample.
- Fetch project-specific values with
get-audience-filter-optionsfor any field marked project-specific that the question uses (project_id,fields). - Call
preview-audiencewithproject_idandbody.rulesin the filter rule shape (for a saved audience fromlist-audiences, passbody.audience_uuidinstead). It is read-only and saves nothing. Do notcreate-audiencejust to inspect a segment. - To rank or name a superlative, pass
sort_by(status,latest_auto_renew_intent,first_seen_at,last_seen_at,total_spent) andsort_direction(ascdefault, ordesc) as top-level parameters, not insidebody.sort_by: total_spentwithsort_direction: descreturns the highest spenders first, so the firstcustomer_samplerow is the top spender. The sample is capped (typically 50): it is the top or bottom matches, not every customer. - Answer "how many" from
stats(total_customers,active_subscriptions,active_trials,total_revenueincurrency), never from the sample size. Whenstats.is_approximateis true, give counts and revenue as approximate ("about 6,400 customers"). - Name customers only from fields
customer_samplereturned (app_user_id,email,status,total_spent,latest_product_name, first/last seen). Withoutsort_bythe sample is unordered: say it is a sample of matches, not a ranking. totalRenewalsis a filter only, not asort_byvalue or a sample column. Filter on a high threshold and report the matches; do not invent a renewal count or claim a unique maximum.- Share the dashboard link. The
preview-audienceresult forbody.rulesincludes a line starting "Dashboard URL for this result"; link that exact URL. Build one yourself (constructing a link) only when no tool result gave you a URL.
Constructing a link
Use this only when no tool result gave you a "Dashboard URL for this result" line. Two shapes: a
filtered all-customers link for ad-hoc exploration, and a saved-audience link after
create-audience.
- Get the project ID from
list-projects. For dashboard URLs, strip theprojprefix. - Pick fields and operators from the field tables. Do not invent field or operator names.
- For project-specific fields, fetch valid values with
get-audience-filter-optionsfirst. - Assemble the rule JSON: one group per OR-branch, conditions inside a group for AND, values encoded per value formats.
- Serialize and URL-encode the rule with a short script (see encoding the rule) — do not encode by hand.
- Append it as the
filtersquery param onhttps://app.revenuecat.com/projects/{project_id}/customer-lists/all-customers.
URL format
https://app.revenuecat.com/projects/{project_id}/customer-lists/all-customers?filters={encoded_rule}
{project_id}— short hex ID fromlist-projectswithprojstripped.- Filters only work on the
all-customerslist. The unfiltered Audiences home is/projects/{project_id}/customer-lists.
Linking to a saved audience
The create-audience and get-audience results include a "Dashboard URL for this result" line;
link that exact URL. If you only have list-audiences output, link with customer_list_id, the
field returned alongside id:
https://app.revenuecat.com/projects/{project_id}/customer-lists/{customer_list_id}
An audience's id (aud…) and its customer_list_id (list…) are different identifiers.
The dashboard route only resolves customer_list_id; an aud… id in that slot renders
"Audience not found".
Correct:
https://app.revenuecat.com/projects/56965ae1/customer-lists/list7c1f0a2b93
Wrong (the audience id instead of the customer_list_id):
https://app.revenuecat.com/projects/56965ae1/customer-lists/audf0269cdf3df84dd2
Do not add a filters param to a saved-audience link — the audience carries its own rules. If
the response has no customer_list_id, link to /customer-lists and name the audience rather
than guessing an id.
Offering to save the filtered view
A filtered all-customers link is ad-hoc — nothing about it is saved. Say so in one short
sentence when you share one, and offer to save it: "This view isn't saved — want me to save it
as an audience so you can find it later?"
Offer once per conversation. If they accept, call create-audience with the same rule you built
for the link, then link to it. Do not offer when the link is already to a saved audience.
The filter rule
The filters value is URL-encoded JSON with this shape:
{
"groups": [
{
"conditions": [{ "field": "platform", "operator": "is", "value": "android" }]
}
]
}
- Conditions within a group combine with AND.
- Groups combine with OR.
valueis always a JSON string — booleans as"true"/"false", numbers as"42", lists as a comma-separated string, date ranges and relative dates as stringified JSON (see value formats).
Correct (compact JSON, whole value URL-encoded):
?filters=%7B%22groups%22%3A%5B%7B%22conditions%22%3A%5B%7B%22field%22%3A%22platform%22%2C%22operator%22%3A%22is%22%2C%22value%22%3A%22android%22%7D%5D%7D%5D%7D
Wrong (raw JSON, spaces, unencoded quotes/braces):
?filters={"groups": [{"conditions": [...]}]}
Encoding the rule
import json
from urllib.parse import quote
rule = {
"groups": [
{"conditions": [{"field": "platform", "operator": "is", "value": "android"}]},
]
}
print(quote(json.dumps(rule, separators=(",", ":")), safe=""))
Fields
The Audiences preview table shows only Customer, Subscription Status, Auto-Renewal Status, Spent, and Latest Purchase. Other attributes appear in the CSV from Export all, or on a customer's profile.
Use these exact field strings. See
Audiences.
Text fields
Operators: is, isNot, contains, doesNotContain, isEmpty, isNotEmpty.
| Field | Meaning |
|---|---|
customerId | App user ID |
originalAppUserId | Original app user ID |
email | |
phoneNumber | Phone number |
locale | Locale |
appVersion | App version |
sdkVersion | SDK version |
platformVersion | Platform (OS) version |
projectId | Project ID (e.g. proj1ab2c3d4) |
projectName | Project name |
appConfigId | App ID (e.g. app1ab2c3d4) |
appConfigName | App name |
idfa | IDFA |
idfv | IDFV |
gpsAdId | GPS ad ID |
latestPurchasedOffering | Latest purchased offering |
latestOffer | Latest offer identifier |
latestEntitlements | Latest entitlement identifiers |
allPurchasedProductIds | All purchased product identifiers |
Enum fields
Operators: is, isNot, isAnyOf, isNotAnyOf, isEmpty, isNotEmpty.
| Field | Values |
|---|---|
platform | iOS, android, web, macOS, amazon, roku, tvOS, visionOS, watchOS |
status | active, trialing, in_grace_period, in_billing_retry, paused, expired, incomplete, unknown |
latestStore | app_store, play_store, promotional, mac_app_store, stripe, amazon, roku, rc_billing, paddle, external |
anyActiveStore | Any active store — same store identifiers as latestStore |
latestOwnershipType | PURCHASED, FAMILY_SHARED |
latestOfferType | no_offer, free_trial, introductory_offer, offer_code, promotional_offer, win_back_offer, unspecified_offer |
priceExperimentVariant | a, b, c, d |
country | Last seen country — ISO 3166-1 alpha-2 codes (e.g. US, DE) |
latestStoreCountry | ISO 3166-1 alpha-2 country codes |
storefront | Store country — ISO 3166-1 alpha-2 codes |
mediaSource | project-specific — fetch valid values |
campaign | project-specific |
adGroup | project-specific |
ad | project-specific |
keyword | project-specific |
creative | project-specific |
priceExperimentId | project-specific |
latestProduct | product IDs of the project — fetch valid values |
Boolean fields
Operators: is, isNot. Value is exactly "true" or "false".
| Field | Meaning |
|---|---|
hasMadeSandboxPurchase | Has made a sandbox purchase |
hasMadeNonSubscriptionPurchase | Has made a non-subscription purchase |
latestAutoRenewIntent | Auto-renewal status (true = set to renew) |
isCurrentlyTrialing | Currently trialing |
isRcPromo | Has been granted an entitlement via RC (promotional) |
Number fields
Operators: equal, notEqual, greaterThan, greaterThanOrEqual, lessThan,
lessThanOrEqual, isEmpty, isNotEmpty. Value is a numeric string, e.g. "50".
| Field | Meaning |
|---|---|
totalSpent | Total spent |
totalRenewals | Total number of renewals |
Date fields
Operators: before, beforeOrOn, on, after, afterOrOn, within, between, notBetween,
isEmpty, isNotEmpty.
| Field | Meaning |
|---|---|
firstSeenAt | First seen |
lastSeenAt | Last seen |
firstPurchaseAt | First purchase |
mostRecentPurchaseAt | Most recent purchase |
mostRecentRenewalAt | Most recent renewal |
latestExpirationAt | Latest expiration |
trialStartAt | Trial start |
trialEndAt | Trial end |
subscriptionOptOutAt | Most recent cancellation |
trialOptOutAt | Most recent trial cancellation |
Custom attribute fields
Filter with customAttribute:{key} (e.g. customAttribute:favorite_team). They use the enum
operators. Fetch known keys and values with get-audience-filter-options — never invent a key.
Value formats
isEmpty/isNotEmpty— set"value": ""(the value is ignored).isAnyOf/isNotAnyOf— comma-separated string:"value": "US,CA,MX".before,beforeOrOn,on,after,afterOrOn— calendar date"value": "2026-01-31"(YYYY-MM-DD).between/notBetween— stringified JSON with exactlyfromandto:"value": "{\"from\":\"2026-01-01\",\"to\":\"2026-01-31\"}"(from≤to).within— stringified JSON with exactlydirection,value,unit:"value": "{\"direction\":\"last\",\"value\":30,\"unit\":\"days\"}".directionislastornext;unitisminutes,hours, ordays;valueis a non-negative integer.before/beforeOrOn/after/afterOrOnalso accept this relative format (noton).
Fetching project-specific values
Fields marked project-specific (mediaSource, campaign, adGroup, ad, keyword, creative,
priceExperimentId, latestProduct) and custom attributes only match values that exist in the
project's data. Fetch with get-audience-filter-options:
project_id(required)fields(required, at least one) — any of the eight fields above,customAttribute:{key}for one custom attribute, orcustomAttributeto list every custom attribute key with its values.
A custom-attribute entry may come back with cardinality_exceeded: true — a value the user
stated verbatim can still be valid even if it is not in the list.
Fixed-value fields (country, platform, status, …) are not served by this tool — use the
tables above. Never guess project-specific values — a filter on a non-existent value silently
matches zero customers.
Example: building a link
User wants: "Android customers acquired through Instagram" in project proj56965ae1.
Rule (both conditions in one group — AND):
{
"groups": [
{
"conditions": [
{ "field": "platform", "operator": "is", "value": "android" },
{ "field": "mediaSource", "operator": "is", "value": "Instagram" }
]
}
]
}
Link:
https://app.revenuecat.com/projects/56965ae1/customer-lists/all-customers?filters=%7B%22groups%22%3A%5B%7B%22conditions%22%3A%5B%7B%22field%22%3A%22platform%22%2C%22operator%22%3A%22is%22%2C%22value%22%3A%22android%22%7D%2C%7B%22field%22%3A%22mediaSource%22%2C%22operator%22%3A%22is%22%2C%22value%22%3A%22Instagram%22%7D%5D%7D%5D%7D
User wants: "customers on iOS or Android who are currently trialing and were first seen in the last 30 days".
{
"groups": [
{
"conditions": [
{ "field": "platform", "operator": "isAnyOf", "value": "iOS,android" },
{ "field": "isCurrentlyTrialing", "operator": "is", "value": "true" },
{
"field": "firstSeenAt",
"operator": "within",
"value": "{\"direction\":\"last\",\"value\":30,\"unit\":\"days\"}"
}
]
}
]
}
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/revenuecat/ai-toolkit/revenuecat-audiences">View revenuecat-audiences on skillZs</a>