User Traits
rybbit_get_user_traitsRetrieve user trait data from Rybbit Analytics: list trait keys, view distinct values for specific keys, or find users matching trait criteria to analyze user behavior and segmentation.
Instructions
Get user trait keys, values, or find users by trait. mode='keys' lists all trait keys. mode='values' (default when key is provided) returns distinct values for a trait key. mode='users' finds users matching a specific trait key+value pair (case-insensitive).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| siteId | Yes | Site ID (numeric ID or domain identifier) | |
| mode | No | 'keys' to list trait keys, 'values' to get values for a key, 'users' to find users by trait. Default: 'keys' if no key provided, 'values' if key is provided. | |
| key | No | Trait key (required for 'values' and 'users' modes) | |
| value | No | Trait value (required for 'users' mode) | |
| limit | No | Max results to return |
Implementation Reference
- src/tools/users.ts:248-289 (handler)The handler logic for the rybbit_get_user_traits tool, which determines the mode ('keys', 'values', 'users') and fetches data from the appropriate API endpoint.
async (args) => { try { let data: unknown; const resolvedMode = args.mode ?? (args.key ? "values" : "keys"); if (resolvedMode === "users") { // API does exact (case-sensitive) match, so resolve the correct case first let resolvedValue = args.value; if (args.key && args.value) { const valuesData = await client.get<{ values: { value: string }[] }>( `/sites/${args.siteId}/user-traits/values`, { key: args.key, limit: 1000 } ); const match = valuesData.values?.find( (v) => v.value.toLowerCase() === args.value!.toLowerCase() ); if (match) resolvedValue = match.value; } const params: Record<string, string | number> = {}; if (args.key !== undefined) params.key = args.key; if (resolvedValue !== undefined) params.value = resolvedValue; if (args.limit !== undefined) params.limit = args.limit; data = await client.get(`/sites/${args.siteId}/user-traits/users`, params); } else if (resolvedMode === "values" && args.key !== undefined) { const params: Record<string, string | number> = { key: args.key }; if (args.limit !== undefined) params.limit = args.limit; data = await client.get(`/sites/${args.siteId}/user-traits/values`, params); } else { data = await client.get(`/sites/${args.siteId}/user-traits/keys`); } return { content: [{ type: "text" as const, text: truncateResponse(data) }], }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } } ); - src/tools/users.ts:222-289 (registration)The registration of the rybbit_get_user_traits tool, including its metadata, description, and input schema.
server.registerTool( "rybbit_get_user_traits", { title: "User Traits", annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true, destructiveHint: false }, description: "Get user trait keys, values, or find users by trait. mode='keys' lists all trait keys. mode='values' (default when key is provided) returns distinct values for a trait key. mode='users' finds users matching a specific trait key+value pair (case-insensitive).", inputSchema: { siteId: siteIdSchema, mode: z .enum(["keys", "values", "users"]) .optional() .describe("'keys' to list trait keys, 'values' to get values for a key, 'users' to find users by trait. Default: 'keys' if no key provided, 'values' if key is provided."), key: z .string() .optional() .describe( "Trait key (required for 'values' and 'users' modes)" ), value: z .string() .optional() .describe("Trait value (required for 'users' mode)"), limit: z.number().optional().describe("Max results to return"), }, }, async (args) => { try { let data: unknown; const resolvedMode = args.mode ?? (args.key ? "values" : "keys"); if (resolvedMode === "users") { // API does exact (case-sensitive) match, so resolve the correct case first let resolvedValue = args.value; if (args.key && args.value) { const valuesData = await client.get<{ values: { value: string }[] }>( `/sites/${args.siteId}/user-traits/values`, { key: args.key, limit: 1000 } ); const match = valuesData.values?.find( (v) => v.value.toLowerCase() === args.value!.toLowerCase() ); if (match) resolvedValue = match.value; } const params: Record<string, string | number> = {}; if (args.key !== undefined) params.key = args.key; if (resolvedValue !== undefined) params.value = resolvedValue; if (args.limit !== undefined) params.limit = args.limit; data = await client.get(`/sites/${args.siteId}/user-traits/users`, params); } else if (resolvedMode === "values" && args.key !== undefined) { const params: Record<string, string | number> = { key: args.key }; if (args.limit !== undefined) params.limit = args.limit; data = await client.get(`/sites/${args.siteId}/user-traits/values`, params); } else { data = await client.get(`/sites/${args.siteId}/user-traits/keys`); } return { content: [{ type: "text" as const, text: truncateResponse(data) }], }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } } );