buildPendoSegment: Purpose: Describe one visitor segment by visitor or account ID, activity on Pages, Features, TrackEvents, Guides, Poll responses, the elements inside a guide, segment membership, or metadata. Input shape: pass definition as an array of rule groups. Top-level groups are ANDed together; rules within a group are ORed together. For one ANDed rule, wrap it in a single-item group.
SINGLE CALL CONTRACT (important): The ENTIRE segment, including every AND clause and every OR clause, MUST be built with ONE call to this tool. Never split a segment across multiple calls. Combine all clauses into a single definition array and pass it once. Calling the tool more than once produces multiple unrelated segments, NOT one combined segment, so the AND/OR logic between the calls is lost.
Mapping a request to a single definition:
- Split the request into top-level AND clauses.
- Each AND clause becomes one group (one inner array) in the definition.
- Inside a clause, every OR alternative becomes one rule object in that group.
- A clause with no OR is a group containing a single rule object.
CLAUSE COVERAGE (important): Account for EVERY clause in the request. Before returning, count the AND clauses in the request and confirm the definition has exactly that many top-level groups, then confirm every OR alternative inside each clause is present as a rule object. Never drop, merge, or skip a clause. If the request mentions a page rule, a feature rule, and a track event rule joined by AND/OR, all of them must appear. A request like "(X OR Y) AND Z" has 2 top-level groups (one for "X OR Y", one for "Z") and 3 rule objects total; returning fewer groups or rules is wrong.
Full example (combining AND and OR in one call): Request: "(visitors who spent > 15 minutes on page A in May OR have NOT seen page B in the last year) AND triggered track event C on fewer than 5 days in the last 7 days" Correct single definition (one tool call): [ [ { "entityType": "page", "entityId": "A", "metric": "eventTime", "operator": ">", "threshold": 15, "condition": "between", "first": "2026-05-01", "last": "2026-05-31" }, { "entityType": "page", "entityId": "B", "metric": "notseen", "condition": "withinLast", "lookbackAmount": 12, "granularity": "months" } ], [ { "entityType": "trackEvent", "entityId": "C", "metric": "daysActive", "operator": "<", "threshold": 5, "condition": "withinLast", "lookbackAmount": 7, "granularity": "days" } ] ] The first group (the two page rules) is ORed together; that group is then ANDed with the second group (the track event rule). This is ONE call, not two.
REQUIRED FIELDS AND CONDITION CHOICE (important): Activity metrics with non-empty supportedConditions MUST include an explicit "condition" field. It is the discriminator that selects which time/frequency fields apply, and it is NOT optional for those metrics. Always choose condition from the chosen metric's supportedConditions. Do NOT rely on the presence of first/last, lookbackAmount/granularity, or date to imply the condition; you must still set condition explicitly for activity metrics. For example:
- first + last present => you MUST also set condition: "between"
- lookbackAmount + granularity => you MUST also set condition: "withinLast"
- date present => you MUST also set condition: "since"
Segment membership metrics are the exception:
- isMemberOfSegment and isNotMemberOfSegment have supportedConditions: [] by design.
- For these metrics, omit "condition" entirely. Do NOT add "ever" or infer any default condition.
- supportedConditions: [] means "no condition field", not "choose a default condition".
Visitor and account ID rules are conditionless and metricless:
- Use entityType: "visitor" or "account".
- Use operator: one of "==", "!=", "contains", "!contains", "empty", "!empty". Omit it to default to "==".
- Use entityId for the comparison value with "==", "!=", "contains", and "!contains".
- Use an empty entityId with "empty" and "!empty".
- Example: { "entityType": "visitor", "entityId": "bob@example.com" }.
- Example: { "entityType": "visitor", "entityId": "@example.com", "operator": "contains" }.
- Example: { "entityType": "account", "entityId": "acme-corp" }.
Metadata rules are also conditionless and metricless:
- Use entityType: "metadata".
- Use entityId for the full metadata key, e.g. "visitor.agent.job_role".
- Use operator: one of "==", "!=", ">=", "<=", "contains", "!contains", "empty", "!empty".
- Use value for "==", "!=", ">=", "<=", "contains", and "!contains". Omit value for "empty" and "!empty".
- Time and date metadata values may use ISO 8601, e.g. "2025-12-31T23:59:59Z".
- Example: { "entityType": "metadata", "entityId": "visitor.agent.job_role", "operator": "==", "value": "Software engineer" }.
Event-property filters narrow page, feature, or track-event aggregation rules by a property on each event:
- Add one eventProperty object with property, operator, and (except for empty/!empty) value.
- For a custom event property, use its plain property name. Custom properties are supported on feature and trackEvent rules.
- For historical metadata captured on an event, use kind.group.field, e.g. "visitor.agent.user_job_role".
Historical metadata is supported on page, feature, and trackEvent rules.
- Event properties require an aggregation metric such as eventCount or daysActive; they cannot be added to seen/used counter metrics.
- Use listCountables eventPropertyNames to discover custom properties. Historical metadata must currently be promoted.
- Example: visitors who ran a report with the "source" filter in the last 30 days:
[ [ { "entityType": "trackEvent", "entityId": "<reportRanTrackEventId>", "metric": "eventCount", "operator": ">=", "threshold": 1, "condition": "withinLast", "lookbackAmount": 30, "granularity": "days", "eventProperty": { "property": "filter", "operator": "==", "value": "source" } } ] ]
Guide element rules cover clicks on one button, link or close icon inside a guide:
- Use entityType: "guideElement".
- Use entityId for the GUIDE id, stepId for the step the element sits on, and elementId for the
element's uiElementId, e.g. { "entityType": "guideElement", "entityId": "<guideId>", "stepId": "<guideStepId>", "elementId": "pendo-button-a1b2c3d4", "metric": "eventCount", "operator": ">=", "threshold": 1, "condition": "withinLast", "lookbackAmount": 30, "granularity": "days" }.
- One getEntity call gives both ids: steps[].stepId and the
steps[].elements[].uiElementId nested under it. Never guess either.
- eventCount is the only supported metric, and it counts clicks on that element in the chosen window:
- "clicked it" => operator ">=", threshold 1
- "did not click it" => operator "==", threshold 0
- click counts => any operator, e.g. "clicked it more than 3 times" is operator ">", threshold 3
- stepId does not narrow the count.
- Only withinLast and between are available, so a click rule is always scoped to a window.
Poll response rules select visitors by a numeric poll response:
- Use entityType: "poll", entityId for the guide id, and pollId for its poll.
- Resolve pollId from getEntity's guide steps[].polls[] output; select the poll whose type is the poll type.
Never guess a pollId.
- Use metric: "response", a numeric operator and threshold, plus a supported condition.
- Conditions ever, since (with date), withinLast, and between are supported. A response range requires two separate top-level AND groups, not one OR group. For example, responses from 7 through 10 in the last 30 days:
[ [{ "entityType": "poll", "entityId": "<surveyGuideId>", "pollId": "<pollId>", "metric": "response", "operator": ">=", "threshold": 7, "condition": "withinLast", "lookbackAmount": 30, "granularity": "days" }], [{ "entityType": "poll", "entityId": "<surveyGuideId>", "pollId": "<pollId>", "metric": "response", "operator": "<=", "threshold": 10, "condition": "withinLast", "lookbackAmount": 30, "granularity": "days" }] ]
Resolution steps 1. Choose entityType from EntityTypes. 2. For visitor or account, use entityId + optional operator and stop here. 3. For metadata, use entityId + operator + optional value and stop here. 4. For activity and segment entities, choose metric from EntityTypes[entityType].supportedMetrics. 5. Look up Metrics[metric]. 6. If Metrics[metric].supportedConditions is non-empty, choose condition from that list and look up Conditions[condition]. 7. The final rule fields are: EntityTypes[entityType].requiredFields + Metrics[metric].requiredFields + Conditions[condition].requiredFields, only when a condition is required.
Time phrase resolution examples:
- "this year" / "so far this year" / "year to date" => condition: "since", date: "2026-01-01"
- "this month" / "month to date" => condition: "since", date: "2026-06-01"
- "since 2026-01-01" => condition: "since", date: "2026-01-01"
- "last year" => condition: "between", first: "2025-01-01", last: "2025-12-31"
- "in the last year" => condition: "withinLast", lookbackAmount: 12, granularity: "months"
- "between 2026-01-01 and 2026-06-05" => condition: "between", first: "2026-01-01", last: "2026-06-05"
- "in March" => condition: "between", first: "2026-03-01", last: "2026-03-31"
- "last 3 weeks" => condition: "withinLast", lookbackAmount: 3, granularity: "weeks"
- "last 7 days" => condition: "withinLast", lookbackAmount: 7, granularity: "days"
CONDITION CHOICE FOR TIME PHRASES (important):
- Use "since" (set only date) for any open-ended period running from a start date up to now:
"this year", "this month", "year to date", "so far", "since <date>". Do NOT express these as "between ... today".
- Use "between" (set first + last) ONLY for a closed range whose end is a specific past date or the last
day of a named calendar period (e.g. "in March", "last year", "between X and Y").
- Use "withinLast" (set lookbackAmount + granularity) for rolling windows: "last N days/weeks/months".
- Set ONLY the fields the chosen condition requires. Never combine date with first/last in one rule.
A segment should be just as valid in a week's time as it is today, so never hardcode today's date as an endpoint. For a fixed/named calendar period (e.g. "in March") use "between" spanning the entire period even if it has not finished yet. For an open-ended current period (e.g. "this year", "this month") use "since" with the period's start date, which stays valid going forward. EntityTypes: visitor: requiredFields: entityType: "visitor" entityId: String supportedMetrics: []
account: requiredFields: entityType: "account" entityId: String supportedMetrics: []
page: requiredFields: entityType: "page" entityId: String supportedMetrics: ["eventCount", "deadClicks", "errorClicks", "rageClicks", "daysActive", "uTurns", "eventTime", "seen", "notseen", "lastSeen"]
feature: requiredFields: entityType: "feature" entityId: String supportedMetrics: ["eventCount", "deadClicks", "errorClicks", "rageClicks", "daysActive", "used", "notused", "lastused"]
trackEvent: requiredFields: entityType: "trackEvent" entityId: String supportedMetrics: ["eventCount", "daysActive", "used", "notused", "lastused"]
guide: requiredFields: entityType: "guide" entityId: String supportedMetrics: ["seen", "lastSeen", "notSeen"]
poll: requiredFields: entityType: "poll" entityId: String pollId: String // the poll nested under the guide supportedMetrics: ["response"]
guideElement: requiredFields: entityType: "guideElement" entityId: String stepId: String // the guide step the element sits on elementId: String // the element's uiElementId, e.g. "pendo-button-a1b2c3d4" supportedMetrics: ["eventCount"]
segment: requiredFields: entityType: "segment" entityId: String supportedMetrics: ["isMemberOfSegment", "isNotMemberOfSegment"]
metadata: requiredFields: entityType: "metadata" entityId: String supportedMetrics: []
agent: requiredFields: entityType: "agent" entityId: String supportedMetrics: ["eventCount", "daysActive", "used", "notused", "lastused"]
Metrics: eventCount: description: Number of events for the selected entity. requiredFields: metric: "eventCount" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
deadClicks: description: Number of dead clicks for the selected page or feature. requiredFields: metric: "deadClicks" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
errorClicks: description: Number of error clicks for the selected page or feature. requiredFields: metric: "errorClicks" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
rageClicks: description: Number of rage clicks for the selected page or feature. requiredFields: metric: "rageClicks" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
daysActive: description: Number of active days for the selected entity. requiredFields: metric: "daysActive" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
uTurns: description: Number of u-turns for the selected page. requiredFields: metric: "uTurns" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
eventTime: description: Time in minutes spent on the selected page. requiredFields: metric: "eventTime" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["withinLast", "between"]
response: description: Numeric poll response. Use two ANDed rules for a range. requiredFields: metric: "response" operator: Enum["==", "!=", ">=", "<="] threshold: Integer supportedConditions: ["ever", "since", "withinLast", "between"]
used: description: Whether the selected feature or track event was used, optionally with a frequency threshold. requiredFields: metric: "used" supportedConditions: ["ever", "since", "withinLast", "atLeast", "atMost"]
notused: description: Whether the selected feature or track event was not used. requiredFields: metric: "notused" supportedConditions: ["ever", "since", "withinLast"]
lastused: description: When the selected feature or track event was last used. requiredFields: metric: "lastused" supportedConditions: ["since", "withinLast", "between"]
seen: description: Whether the selected page was seen, optionally with a frequency threshold. For checking withinLast requiredFields: metric: "seen" supportedConditions: ["ever", "since", "withinLast", "atLeast", "atMost"]
notseen: description: Whether the selected page was not seen. requiredFields: metric: "notseen" supportedConditions: ["ever", "since", "withinLast"]
lastSeen: description: When the selected page was last seen. requiredFields: metric: "lastSeen" supportedConditions: ["since", "withinLast", "between"]
isMemberOfSegment: description: Whether the visitor is a member of the selected segment. requiredFields: metric: "isMemberOfSegment" supportedConditions: []
isNotMemberOfSegment: description: Whether the visitor is not a member of the selected segment. requiredFields: metric: "isNotMemberOfSegment" supportedConditions: []
Conditions: ever: description: The metric happened at any time. requiredFields: condition: "ever"
since: description: The metric happened on or after a specific date. requiredFields: condition: "since" date: DateString("yyyy-mm-dd")
withinLast: description: The metric happened within a rolling time window. requiredFields: condition: "withinLast" lookbackAmount: Integer granularity: Enum["days", "weeks", "months"]
between: description: The metric happened within an inclusive date range. requiredFields: condition: "between" first: DateString("yyyy-mm-dd") last: DateString("yyyy-mm-dd")
atLeast: description: The metric happened at least threshold times ever requiredFields: condition: "atLeast" threshold: Integer
atMost: description: The metric happened at most threshold times ever requiredFields: condition: "atMost" threshold: Integer