Skip to main content
Glama
arttus

umami-mcp-server

by arttus

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
UMAMI_REGIONNoUmami Cloud region: 'us' or 'eu'. Defaults to the key owner's region.
UMAMI_API_KEYNoUmami API key. Required for Umami Cloud, or as one of the two authentication methods for self-hosted instances.
UMAMI_BASE_URLNoRoot URL of a self-hosted Umami instance, e.g. https://analytics.example.com. The /api suffix is added automatically.
UMAMI_PASSWORDNoLogin password for self-hosted Umami, used together with UMAMI_USERNAME instead of an API key.
UMAMI_TIMEZONENoIANA timezone for day boundaries and time-series buckets, e.g. America/New_York.UTC
UMAMI_USERNAMENoLogin username for self-hosted Umami, used together with UMAMI_PASSWORD instead of an API key.
UMAMI_DEFAULT_WEBSITENoWebsite ID, name, or domain used when a tool call omits 'website'.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
umami_list_websitesA

List every website tracked in this Umami account, including websites owned by teams.

Start here when you do not already know a website ID. Every other tool accepts a website ID, name, or domain, so this tool is what turns "the marketing site" into something queryable.

Args:

  • search (string, optional): Case-insensitive substring matched against name and domain.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "count": number, "websites": [ { "id": string, "name": string, "domain": string, "created_at": string, "team_id": string | null } ] }

Examples:

  • "What sites do I have in Umami?" -> no arguments

  • "Find the website for example.com" -> search="example.com"

Error handling:

  • Returns an authentication error if the API key or login is rejected.

  • Returns "No websites found" when the account has none.

umami_get_websiteA

Get configuration details for one website plus the date range of data actually collected for it.

The date range matters: querying a period before tracking started returns zeros, which is easy to misread as a traffic collapse. Check this first when numbers look surprisingly empty.

Args:

  • website (string, optional): Website ID, name, or domain.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "id": string, "name": string, "domain": string, "share_id": string | null, "created_at": string, "data_start": string | null, "data_end": string | null, "active_visitors": number }

Examples:

  • "When did we start tracking example.com?" -> website="example.com"

  • "Is anyone on the site right now?" -> website="example.com"

umami_get_active_visitorsA

Get the number of unique visitors active on a website in the last 5 minutes.

This is the realtime counter only. For traffic over a period use umami_get_stats.

Args:

  • website (string, optional): Website ID, name, or domain.

Returns: JSON shape: { "website_id": string, "active_visitors": number, "window": "last 5 minutes" }

Examples:

  • "How many people are on the site right now?" -> website="example.com"

umami_get_statsA

Get summary traffic statistics for a website over a date range, with optional comparison to the immediately preceding period.

This is the headline-numbers tool: pageviews, visitors, visits, bounce rate, and average visit duration. Bounce rate and average visit duration are derived here, since Umami returns raw bounce and total-time counts.

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '7d'. Relative ('24h', '7d', '30d'), named ('today', 'yesterday', 'last_week', 'last_month', 'mtd', 'ytd'), or use start_date/end_date.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • compare (boolean): Also return the previous period of equal length with percent change (default: true).

  • filters (object, optional): Segment filters such as { country: 'US', path: '/pricing' }.

  • timezone (string, optional): IANA timezone for day boundaries.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "website_id": string, "range": { "start": string, "end": string }, "stats": { "pageviews": number, "visitors": number, "visits": number, "bounces": number, "totaltime": number, "bounce_rate_pct": number, "views_per_visit": number, "avg_visit_duration_seconds": number }, "previous": { ...same fields... } | null, "change": { "pageviews": string, "visitors": string, "visits": string, "bounce_rate_pct": string } | null }

Examples:

  • "How did the site do last month?" -> range="last_month"

  • "Traffic from mobile users in the US this week" -> range="this_week", filters={ device: "mobile", country: "US" }

  • "Compare this month to last" -> range="mtd", compare=true

Error handling:

  • Returns a 404 error if the website ID does not exist.

  • All-zero results usually mean the range predates tracking; check umami_get_website for the available data range.

umami_get_pageviews_seriesA

Get pageviews and sessions bucketed over time, for trend and seasonality questions.

Use this when the question is about shape over time rather than a single total: which day spiked, whether traffic is trending up, what the weekday pattern looks like.

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • unit ('minute' | 'hour' | 'day' | 'month' | 'year', optional): Bucket size. Chosen automatically if omitted. Umami caps minute at 60 minutes, hour at 30 days, day at 6 months.

  • filters (object, optional): Segment filters.

  • timezone (string, optional): IANA timezone for bucket boundaries.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "website_id": string, "unit": string, "points": [ { "timestamp": string, "pageviews": number, "sessions": number } ], "totals": { "pageviews": number, "sessions": number }, "peak": { "timestamp": string, "pageviews": number } }

Examples:

  • "Show daily traffic for the last 30 days" -> range="30d", unit="day"

  • "What hour of the day is busiest?" -> range="24h", unit="hour"

umami_get_events_seriesA

Get counts of custom tracked events bucketed over time, grouped by event name.

Use this for conversion and interaction tracking: form submits, button clicks, signups, or any event fired through umami.track().

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • unit ('minute' | 'hour' | 'day' | 'month' | 'year', optional): Bucket size, chosen automatically if omitted.

  • event (string, optional): Restrict to a single event name.

  • filters (object, optional): Segment filters.

  • timezone (string, optional): IANA timezone.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "website_id": string, "unit": string, "totals_by_event": { "": number }, "series": [ { "event": string, "timestamp": string, "count": number } ] }

Examples:

  • "How many contact form submits last week?" -> range="last_week", event="contact-form-submit"

  • "Which events fire most often?" -> range="30d"

umami_get_metricsA

Get a ranked breakdown of traffic by one dimension: top pages, referrers, countries, browsers, devices, acquisition channels, custom events, and more.

This is the workhorse for "top N" questions. Set expanded=true when you need engagement quality per row (pageviews, visitors, visits, bounces, time on site) rather than just a visitor count, for example to find which landing page bounces hardest.

Args:

  • website (string, optional): Website ID, name, or domain.

  • type (string, required): Dimension to break down by. 'path' (pages), 'entry' (landing pages), 'exit', 'referrer', 'channel', 'domain', 'country', 'region', 'city', 'browser', 'os', 'device', 'language', 'screen', 'title', 'query', 'event', 'hostname', 'tag', 'distinctId'.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • expanded (boolean): Return per-row engagement metrics instead of a single count (default: false).

  • limit (number): Rows to return, 1-500 (default: 20).

  • offset (number): Rows to skip for pagination (default: 0).

  • filters (object, optional): Segment filters, for example { country: 'US' } to see top pages among US visitors.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: Plain JSON shape: { "type": string, "count": number, "rows": [ { "name": string, "visitors": number, "share_pct": number } ], "has_more": boolean, "next_offset": number } Expanded JSON shape: { "type": string, "count": number, "rows": [ { "name": string, "pageviews": number, "visitors": number, "visits": number, "bounces": number, "bounce_rate_pct": number, "avg_visit_duration_seconds": number } ], ... }

Examples:

  • "What are our top 10 pages this month?" -> type="path", range="this_month", limit=10

  • "Where is traffic coming from?" -> type="referrer", range="30d"

  • "Which landing page has the worst bounce rate?" -> type="entry", expanded=true

  • "Top pages for mobile visitors in Florida" -> type="path", filters={ device: "mobile", region: "US-FL" }

Error handling:

  • Returns "No data" when the dimension has no rows in the range, which is expected for 'event' when no custom events are tracked.

umami_list_sessionsA

List individual visitor sessions for a website over a date range, newest first.

Sessions are anonymous. Use this to inspect real visit behaviour rather than aggregates: how many pages a typical visit covers, where high-engagement visitors come from, or what a spike actually consisted of.

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • search (string, optional): Free-text search across session attributes.

  • page (number): Page number, 1-based (default: 1).

  • page_size (number): Sessions per page, 1-100 (default: 20).

  • filters (object, optional): Segment filters such as { country: 'US' }.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "total": number, "page": number, "page_size": number, "sessions": [ { "id": string, "country": string, "city": string, "device": string, "browser": string, "os": string, "first_at": string, "last_at": string, "visits": number, "views": number } ], "has_more": boolean }

Examples:

  • "Show me sessions from yesterday" -> range="yesterday"

  • "Which visits looked at the most pages this week?" -> range="this_week", page_size=50

Error handling:

  • Returns an empty result set when no sessions occurred in the range.

umami_get_sessionA

Get details for one visitor session, optionally including the full page-by-page activity trail.

Use this to trace an individual journey through the site: entry page, path taken, events fired, exit point. Get session IDs from umami_list_sessions with response_format='json'.

Args:

  • website (string, optional): Website ID, name, or domain.

  • session_id (string, required): Session UUID.

  • include_activity (boolean): Include the chronological page and event trail (default: true).

  • range (string): Date range to search for activity, default '30d'. Activity outside this range is not returned.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "session": { "id": string, "country": string, "device": string, "browser": string, "os": string, "first_at": string, "last_at": string, "visits": number, "views": number, "events": number, "totaltime": number }, "activity": [ { "created_at": string, "url_path": string, "referrer_domain": string, "event_name": string } ] }

Examples:

  • "What did session abc123 do on the site?" -> session_id="abc123...", include_activity=true

umami_traffic_reportA

Build a complete traffic report for a website in one call: headline stats, period-over-period change, and ranked breakdowns for top pages, landing pages, referrers, acquisition channels, countries, devices, and browsers.

Prefer this over chaining umami_get_stats and several umami_get_metrics calls when the question is broad, for example "how is the site doing" or "give me last month's analytics". Use the individual tools instead when you need one specific dimension, deeper pagination, or expanded engagement metrics.

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '30d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • breakdowns (array of strings, optional): Which dimensions to include. Defaults to path, entry, referrer, channel, country, device, browser.

  • limit (number): Rows per breakdown, 1-50 (default: 10).

  • compare (boolean): Include the previous period of equal length with percent change (default: true).

  • filters (object, optional): Segment filters applied to every part of the report.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "website": string, "range": { "start": string, "end": string }, "stats": { "pageviews": number, "visitors": number, "visits": number, "bounce_rate_pct": number, "avg_visit_duration_seconds": number }, "change": { "pageviews": string, "visitors": string, "visits": string } | null, "breakdowns": { "": [ { "name": string, "visitors": number, "share_pct": number } ] } }

Examples:

  • "Give me the analytics rundown for last month" -> range="last_month"

  • "How did the site do this week versus last?" -> range="this_week", compare=true

  • "Full report for US mobile traffic" -> filters={ country: "US", device: "mobile" }

Error handling:

  • Individual breakdowns that fail are omitted rather than failing the whole report; the response notes which ones were skipped.

umami_create_websiteA

Register a new website for tracking in Umami. This is the first step in onboarding a client or project: it returns a website ID that goes into the tracking script, and that every stats tool in this server uses.

Args:

  • name (string, required): Display name for the website.

  • domain (string, required): The domain being tracked, e.g. 'example.com'. No protocol.

  • team_id (string, optional): Create the website under a team instead of your personal account. Use umami_list_teams to find the ID.

  • id (string, optional): Force a specific UUID for the website, for example to match an ID reserved elsewhere.

Returns: JSON shape: { "id": string, "name": string, "domain": string, "team_id": string | null, "created_at": string, "tracking_snippet": string }

Examples:

  • "Set up tracking for the new client site" -> name="Walker's Land Services", domain="walkerslandservices.com"

  • "Add this under the Gradeline team" -> name="Gradeline", domain="gradeline.info", team_id=""

Error handling:

  • Fails if a website with the same forced 'id' already exists.

  • Not available on Umami Cloud in read-only API-key mode without appropriate account permissions.

umami_update_websiteA

Update a website's name, domain, public share link, or full session replay and heatmap configuration.

Covers every field Umami exposes for a website's recording setup, not just the on/off switches: sampling rates, PII masking strictness, max recording length, and a CSS selector to exclude sensitive elements (payment forms, etc.) from capture. Pass only the fields you want to change; anything omitted is left as-is. Use umami_get_recorder_config afterward to confirm exactly what the tracker will receive.

Args:

  • website (string, required): Website ID, name, or domain.

  • name (string, optional): New display name.

  • domain (string, optional): New domain.

  • share_id (string, optional): Set a custom share slug to enable a public dashboard link. Pass an empty string to disable sharing.

  • replay_enabled (boolean, optional): Enable or disable session replay recording.

  • heatmap_enabled (boolean, optional): Enable or disable heatmap data collection.

  • sample_rate (number, optional): Fraction of sessions to record for replay, 0 to 1.

  • heatmap_sample_rate (number, optional): Fraction of sessions to record for heatmaps, 0 to 1.

  • mask_level ('strict' | 'moderate', optional): PII masking strictness for replay recordings. 'strict' masks more aggressively.

  • max_duration_ms (number, optional): Maximum length of a single recording, in milliseconds. Umami's own docs are inconsistent about whether this field is ms or seconds; umami_get_recorder_config after saving shows the effective value the tracker will actually use.

  • block_selector (string, optional): CSS selector for elements to exclude entirely from replay capture, e.g. '.payment-form, [data-sensitive]'.

Returns: JSON shape: { "id": string, "name": string, "domain": string, "share_id": string | null, "replay_config": { "replayEnabled": boolean, "heatmapEnabled": boolean, "sampleRate": number, "heatmapSampleRate": number, "maskLevel": string, "maxDuration": number, "blockSelector": string } | null }

Examples:

  • "Turn on session replay for the Gradeline site at 20% sampling" -> replay_enabled=true, sample_rate=0.2

  • "Enable heatmaps too, sampled lighter than replay" -> heatmap_enabled=true, heatmap_sample_rate=0.1

  • "Mask more aggressively and exclude the payment form from recordings" -> mask_level="strict", block_selector=".payment-form"

  • "Give this site a public share link" -> share_id="lha-public-dashboard"

  • "Turn off the public link" -> share_id=""

umami_get_recorder_configA

Get the recorder configuration Umami is actually serving to the tracker for a website: whether replay and heatmaps are enabled, sample rates, masking level, max duration, and the block selector.

This reads the same public endpoint the tracker script itself calls, so it is the ground truth after umami_update_website changes replay or heatmap settings, useful for confirming values actually took effect and resolving any unit ambiguity on max duration.

Args:

  • website (string, optional): Website ID, name, or domain.

Returns: JSON shape: { "enabled": boolean, "replay_enabled": boolean, "heatmap_enabled": boolean, "sample_rate": number, "heatmap_sample_rate": number, "mask_level": string, "max_duration": number, "block_selector": string }

Examples:

  • "Did the replay settings actually save?" -> website="example.com"

umami_reset_websiteA

Permanently delete all collected data for a website: every pageview, session, and event. The website registration and tracking ID are kept, so the tracking script keeps working and data collection starts fresh.

This cannot be undone. Requires confirm=true.

Args:

  • website (string, required): Website ID, name, or domain.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "website_id": string }

Examples:

  • "Wipe the test data we collected before going live" -> website="example.com", confirm=true

umami_delete_websiteA

Permanently delete a website registration and all of its collected data from Umami.

This cannot be undone. Requires confirm=true. To keep the registration and tracking ID but clear historical data, use umami_reset_website instead.

Args:

  • website (string, required): Website ID, name, or domain.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "website_id": string }

Examples:

  • "Remove the old staging site from Umami entirely" -> website="staging.example.com", confirm=true

umami_create_userA

Create a new login account on this self-hosted Umami instance. This is for internal team members who need their own login, not for issuing client-facing accounts.

Admin access required. Not available on Umami Cloud.

Args:

  • username (string, required): Login username.

  • password (string, required): Login password. The user can change it after logging in.

  • role ('admin' | 'user' | 'view-only'): Instance-wide role (default: 'user'). 'admin' can manage all users and websites; 'user' can manage their own websites; 'view-only' can only view.

  • id (string, optional): Force a specific UUID for the user.

Returns: { "id": string, "username": string, "role": string }

Examples:

  • "Create a login for the new ops hire" -> username="jordan", password="", role="user"

Error handling:

  • Fails with a 400 if the username is already taken.

  • Fails with 403 if the calling account is not an Umami admin.

umami_list_usersA

List every login account on this self-hosted Umami instance.

Admin access required. Not available on Umami Cloud.

Args:

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "count": number, "users": [ { "id": string, "username": string, "role": string, "created_at": string } ] }

Examples:

  • "Who has a login to our Umami?" -> no arguments

umami_get_userA

Get a login account's details, plus the websites and teams it has access to.

Admin access required for other users; any authenticated user can look up themselves. Not available on Umami Cloud.

Args:

  • user_id (string, required): User UUID. Get this from umami_list_users.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "id": string, "username": string, "role": string, "created_at": string, "websites": [ { "id": string, "name": string, "domain": string } ], "teams": [ { "id": string, "name": string } ] }

umami_update_userA

Change a login account's username, password, or instance-wide role.

Admin access required. Not available on Umami Cloud.

Args:

  • user_id (string, required): User UUID.

  • username (string, optional): New username.

  • password (string, optional): New password.

  • role ('admin' | 'user' | 'view-only', optional): New instance-wide role.

Returns: { "id": string, "username": string, "role": string }

Examples:

  • "Promote jordan to admin" -> user_id="...", role="admin"

  • "Reset their password" -> user_id="...", password=""

umami_delete_userA

Permanently delete a login account from this self-hosted Umami instance. The websites they own are not deleted, but become inaccessible to them.

This cannot be undone. Requires confirm=true. Admin access required. Not available on Umami Cloud.

Args:

  • user_id (string, required): User UUID.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "user_id": string }

umami_create_teamA

Create a team in Umami. Teams group websites and members under shared access, separate from personal accounts. Useful for keeping one client's or one product line's websites together with a dedicated access code.

Args:

  • name (string, required): Team name.

Returns: { "id": string, "name": string, "access_code": string }

The access_code can be shared with someone else so they can self-join via umami_join_team, instead of you adding them one by one.

Examples:

  • "Create a team to hold all the Gradeline sites" -> name="Gradeline"

umami_list_teamsA

List every team on this Umami account, with member and website counts.

Args:

  • limit (number): Rows to return, 1-500 (default: 20).

  • offset (number): Rows to skip, converted to a page number (default: 0).

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "count": number, "teams": [ { "id": string, "name": string, "access_code": string, "website_count": number, "member_count": number } ] }

Examples:

  • "What teams do we have set up?" -> no arguments

umami_get_teamA

Get a team's details, including its full member list and roles.

Args:

  • team_id (string, required): Team UUID. Get this from umami_list_teams.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "id": string, "name": string, "access_code": string, "members": [ { "user_id": string, "username": string, "role": string } ] }

umami_get_team_websitesA

List every website belonging to a team.

Args:

  • team_id (string, required): Team UUID.

  • search (string, optional): Case-insensitive substring to filter by name or domain.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "count": number, "websites": [ { "id": string, "name": string, "domain": string } ] }

umami_update_teamA

Update a team's name, or set a new access code.

Args:

  • team_id (string, required): Team UUID.

  • name (string, optional): New team name.

  • access_code (string, optional): New access code for self-join links. Rotating it invalidates the old code.

Returns: { "id": string, "name": string, "access_code": string }

umami_join_teamA

Join a team as the currently authenticated user, using its access code. This is the self-serve counterpart to umami_add_team_user, which an existing team manager uses to add someone else directly.

Args:

  • access_code (string, required): The team's access code, from umami_create_team or umami_get_team.

Returns: { "team_id": string, "user_id": string, "role": string }

umami_add_team_userA

Add an existing Umami login to a team directly, without needing the access code. Requires team-manager or owner permission on the team.

Args:

  • team_id (string, required): Team UUID.

  • user_id (string, required): User UUID to add. Get this from umami_list_users.

  • role ('team-manager' | 'team-member' | 'team-view-only'): Role within the team (default: 'team-member').

Returns: { "team_id": string, "user_id": string, "role": string }

Examples:

  • "Add jordan to the Gradeline team as a manager" -> team_id="...", user_id="...", role="team-manager"

umami_update_team_userA

Change an existing team member's role.

Args:

  • team_id (string, required): Team UUID.

  • user_id (string, required): User UUID whose role should change.

  • role ('team-manager' | 'team-member' | 'team-view-only', required): New role.

Returns: { "team_id": string, "user_id": string, "role": string }

umami_remove_team_userA

Remove a member from a team. Their login and any websites they personally own are unaffected; they simply lose access to the team's shared websites.

Requires confirm=true.

Args:

  • team_id (string, required): Team UUID.

  • user_id (string, required): User UUID to remove.

  • confirm (boolean, required): Must be true.

Returns: { "ok": true, "team_id": string, "user_id": string }

umami_delete_teamA

Permanently delete a team. Websites owned by the team are not deleted, but become inaccessible through it; reassign them first if they still need a home.

This cannot be undone. Requires confirm=true.

Args:

  • team_id (string, required): Team UUID.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "team_id": string }

umami_onboard_clientA

Set up everything Umami needs for a new client or project in a single call: register the website, optionally create a dedicated team for it, and optionally grant an existing internal user access to that team.

This is the fast path for "get this new site tracked and set up properly." For anything more custom, for example multiple websites under one team, use umami_create_website, umami_create_team, and umami_add_team_user individually.

Args:

  • website_name (string, required): Display name for the website.

  • domain (string, required): Domain being tracked, e.g. 'example.com'. No protocol.

  • team_name (string, optional): If given, creates a new team with this name and puts the website under it. Omit to create the website under your personal account instead.

  • grant_user_id (string, optional): An existing internal user (from umami_list_users) to add to the new team.

  • grant_role ('team-manager' | 'team-member' | 'team-view-only'): Role for grant_user_id on the new team (default: 'team-manager'). Ignored if grant_user_id or team_name is omitted.

  • replay_enabled (boolean, optional): Turn on session replay recording for the new website.

  • heatmap_enabled (boolean, optional): Turn on heatmap collection for the new website.

  • sample_rate (number, optional): Fraction of sessions to record for replay, 0 to 1. Only applied if replay_enabled or heatmap_enabled is set.

  • mask_level ('strict' | 'moderate', optional): PII masking strictness for replay recordings.

Returns: JSON shape: { "website": { "id": string, "name": string, "domain": string }, "team": { "id": string, "name": string, "access_code": string } | null, "granted_user": { "id": string, "username": string, "role": string } | null, "replay_config": { "replayEnabled": boolean, "heatmapEnabled": boolean, "sampleRate": number, "maskLevel": string } | null, "tracking_snippet": string }

Examples:

  • "Set up tracking for the new Walker's Land Services site, its own team, and add jordan to it" -> website_name="Walker's Land Services", domain="walkerslandservices.com", team_name="Walker's Land Services", grant_user_id="<jordan's user id>"

  • "Just get this client tracked, no team needed" -> website_name="...", domain="..."

  • "Set it up with replay on at 15% from day one" -> website_name="...", domain="...", replay_enabled=true, sample_rate=0.15

Error handling:

  • If website creation succeeds but team creation fails, the website still exists; the response reports the partial result rather than leaving it unclear.

  • If the website is created but the replay/heatmap follow-up update fails, the website and team (if any) still exist; use umami_update_website to finish that step manually.

umami_get_goalA

Get the conversion rate for a single-step goal: visitors who reached a page, versus all visitors in the same range.

A goal is either a page ('path') or a custom event ('event'). Pass exactly one. Umami has no dedicated goals feature, so this is computed by comparing two filtered calls to the stats endpoint.

Args:

  • website (string, optional): Website ID, name, or domain.

  • path (string): Goal is reaching this page, e.g. '/thank-you'. Exactly one of path/event required.

  • event (string): Goal is firing this custom event, e.g. 'signup'. Exactly one of path/event required.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • filters (object, optional): Segment filters applied to both the goal and the baseline, e.g. { country: 'US' }.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "goal": { "type": "path"|"event", "value": string }, "baseline_visitors": number, "goal_visitors": number, "conversion_rate_pct": number }

Examples:

  • "What % of visitors reach the thank-you page?" -> path="/thank-you"

  • "Conversion rate on the signup event this month" -> event="signup", range="this_month"

Error handling:

  • A goal event with zero occurrences usually means the tracker never fired umami.track(event_name) in the range, not an error.

umami_get_funnelA

Get session counts and drop-off across an ordered sequence of pages and/or custom events.

Umami has no funnel endpoint, so this walks every session's activity trail in the range (capped by max_sessions) looking for the steps in order. A step matches a page path or a custom event name, whichever it equals; a session only advances once it has completed the previous step.

Args:

  • website (string, optional): Website ID, name, or domain.

  • steps (string[], required): 2-8 steps in order, each a page path (e.g. '/pricing') or event name (e.g. 'signup').

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • filters (object, optional): Segment filters applied to the session pool, e.g. { device: 'mobile' }.

  • max_sessions (number): Cap on sessions scanned, default 500, max 2000.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "steps": [ { "step": string, "sessions": number, "pct_of_first": number, "pct_of_previous": number } ], "scanned_sessions": number, "total_sessions_in_range": number, "truncated": boolean }

Examples:

  • "Funnel from pricing to signup to activation" -> steps=["/pricing", "/signup", "activation"]

Error handling:

  • If 'truncated' is true, total sessions in the range exceeded max_sessions; raise it for a more complete picture, at the cost of more API calls.

umami_get_journeysA

Get the most common sequences of pages visitors take through the site.

Umami has no journey/path-analysis endpoint, so this walks every session's activity trail in the range (capped by max_sessions), reduces each to its ordered page paths (consecutive repeats collapsed), truncates to 'depth' steps, and ranks the most frequent sequences.

Args:

  • website (string, optional): Website ID, name, or domain.

  • start_path (string, optional): Only include sessions whose first page matches this path, e.g. '/'.

  • depth (number): Steps per sequence shown, default 4, max 8.

  • limit (number): Top N sequences to return, default 10, max 50.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • filters (object, optional): Segment filters applied to the session pool.

  • max_sessions (number): Cap on sessions scanned, default 500, max 2000.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "sequences": [ { "path": string, "sessions": number, "pct": number } ], "matched_sessions": number, "scanned_sessions": number, "total_sessions_in_range": number, "truncated": boolean }

Examples:

  • "What do people do after landing on the homepage?" -> start_path="/", depth=3

umami_list_replaysA

List recorded session replays for a website over a date range, newest first.

Replays only exist where recording is enabled (umami_get_recorder_config) and a session was sampled. Use umami_get_replay to inspect one in detail.

Args:

  • website (string, optional): Website ID, name, or domain.

  • range (string): Date range, default '7d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • page (number): Page number, 1-based (default: 1).

  • page_size (number): Recordings per page, 1-100 (default: 20).

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "total": number, "page": number, "page_size": number, "replays": [ { "id": string, "session_id": string, "device": string, "browser": string, "os": string, "country": string, "duration_seconds": number, "event_count": number, "started_at": string } ] }

Error handling:

  • An empty result usually means recording is off for this website, or no session was sampled in the range. Check umami_get_recorder_config.

umami_get_replayA

Summarize one recorded session replay: pages visited, click count, and a duration/event breakdown.

This does not return the raw rrweb event stream (it can be tens of thousands of events); it summarizes it. Get replay IDs from umami_list_replays with response_format='json'.

Args:

  • website (string, optional): Website ID, name, or domain.

  • replay_id (string, required): Replay UUID.

  • include_clicks (boolean): Include the raw click coordinates (default: false, capped at 200).

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "session_id": string, "pages": [ { "href": string, "at": string } ], "click_count": number, "clicks": [ { "x": number, "y": number, "pathname": string } ] | undefined }

umami_get_click_heatmapA

Get a click-density heatmap for one page path, built from recorded session replays.

Umami has no dedicated heatmap endpoint. Click coordinates are captured inside session replay recordings, so this filters replays to the given path, downloads them (capped by max_replays), extracts every click's (x, y) position, normalizes it against that recording's viewport size, and buckets it into a grid.

Args:

  • website (string, optional): Website ID, name, or domain.

  • path (string, required): Exact page path to build the heatmap for, e.g. '/pricing'.

  • range (string): Date range, default '30d' (replay volume is usually much lower than pageview volume).

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • grid_size (number): Buckets per axis, default 10 (a 10x10 grid), max 20.

  • max_replays (number): Cap on replays downloaded, default 100, max 300.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "path": string, "sample_replays": number, "replays_with_clicks": number, "total_clicks": number, "grid_size": number, "cells": [ { "row": number, "col": number, "x_pct_range": [number, number], "y_pct_range": [number, number], "clicks": number } ] }

Error handling:

  • Zero clicks usually means recording is off for this page's traffic, sampling missed it, or no one has clicked yet; check umami_list_replays for that path first.

umami_get_retentionA

Get a cohort retention curve: of the distinct visitors seen in the first period, what percentage returned in each period since.

Umami has no retention endpoint. This is built from umami.identify()'d visitors: it groups the 'distinctId' metric dimension by period and measures overlap between the earliest period's cohort and each later period.

Requires the site to call umami.identify(persistentId) with a stable, persistent ID (e.g. a long-lived cookie or logged-in user ID). Without that, every session has a null distinctId and no cohort can be tracked, this will report zero visitors regardless of real traffic.

Args:

  • website (string, optional): Website ID, name, or domain.

  • cohort_unit ('day' | 'week' | 'month'): Length of each period, default 'week'.

  • periods (number): Number of periods to show, including period 0, default 6, max 12.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "cohort_unit": string, "cohort_size": number, "cohort_start": string, "periods": [ { "period": number, "period_start": string, "returning_visitors": number, "retention_pct": number } ] }

Error handling:

  • cohort_size of 0 means no visitor has been identify()'d yet in the earliest period. This is an instrumentation gap, not a data gap; pageview/session tools still work without identify().

umami_get_revenueA

Get total and average revenue from a numeric custom-event property, e.g. an 'amount' field on a 'purchase' event.

Self-hosted Umami has no built-in revenue tracking. This works by reading the distribution of a numeric property recorded on a custom event, via umami.track(event_name, { [property]: amount }). It sums (value x occurrence count) across every recorded value.

Args:

  • website (string, optional): Website ID, name, or domain.

  • event (string, required): Custom event name, e.g. 'purchase'.

  • property (string, required): Numeric property on that event holding the amount, e.g. 'amount'.

  • range (string): Date range, default '30d'.

  • start_date / end_date (string, optional): Explicit bounds, overriding 'range'.

  • filters (object, optional): Segment filters, e.g. { utmSource: 'google' } for revenue by campaign.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "event": string, "property": string, "total_revenue": number, "transaction_count": number, "average_value": number }

Error handling:

  • total_revenue of 0 usually means the tracker has never called umami.track(event, { property: number }) in this range, not an error. Check umami_get_metrics with type='event' to confirm the event fires at all.

umami_create_goalA

Create a persisted Goal that appears under Behavior > Goals in the Umami web UI, not just a computed result. Unlike umami_get_goal (which computes a conversion rate on demand and shows nothing in the UI), this saves the goal definition so it shows up for anyone browsing the dashboard.

Args:

  • website (string, optional): Website ID, name, or domain.

  • name (string, required): Display name for the goal.

  • match_type ('path' | 'event', required): Whether the goal is reaching a page or firing a custom event.

  • value (string, required): The page path (e.g. '/thank-you') or event name (e.g. 'signup') to match.

Returns: { "id": string, "name": string, "type": "goal", "parameters": object }

Error handling:

  • match_type='event' accepts any event name, even one that has never fired yet; the goal will just show 0 conversions until it does.

umami_create_funnelA

Create a persisted Funnel that appears under Behavior > Funnels in the Umami web UI, not just a computed result. Unlike umami_get_funnel (which computes step conversion on demand and shows nothing in the UI), this saves the funnel definition so it shows up for anyone browsing the dashboard.

Args:

  • website (string, optional): Website ID, name, or domain.

  • name (string, required): Display name for the funnel.

  • steps (array, required): 2-8 ordered steps, each { type: 'path' | 'event', value: string }.

  • window_minutes (number): Minutes a session has to complete all steps in order, default 60.

Returns: { "id": string, "name": string, "type": "funnel", "parameters": object }

Examples:

  • "/ -> /audit -> audit_submit funnel" -> steps=[{type:'path',value:'/'},{type:'path',value:'/audit'},{type:'event',value:'audit_submit'}]

umami_list_saved_reportsA

List the saved reports of one type for a website, as they appear in the Umami UI sidebar (Goals, Funnels, Journeys, Retention). For Segments or Cohorts, use umami_list_segments_cohorts instead — they live on a different endpoint.

Args:

  • website (string, optional): Website ID, name, or domain.

  • type (string, required): One of 'goal', 'funnel', 'journey', 'retention'.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "reports": [ { "id": string, "name": string, "type": string, "parameters": object, "created_at": string } ] }

umami_delete_saved_reportA

Permanently delete a saved report (goal, funnel, journey, or retention) so it no longer appears in the Umami UI. Get the report ID from umami_list_saved_reports. For a segment or cohort, use umami_delete_segment_cohort instead.

This cannot be undone. Requires confirm=true.

Args:

  • report_id (string, required): The report's ID.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "report_id": string }

umami_create_segmentA

Create a persisted audience Segment (a saved filter combination) that appears under Audience > Segments in the Umami UI.

Args:

  • website (string, optional): Website ID, name, or domain.

  • name (string, required): Display name for the segment.

  • filters (array, required): 1+ filters, each { dimension, value, is_not? }. Dimension is one of: path, referrer, title, query, browser, os, device, country, region, city, language, hostname, tag, event, distinctId, utmSource, utmMedium, utmCampaign, utmContent, utmTerm, segment, cohort.

  • match ('all' | 'any'): Whether every filter must match, or just one (default: 'all').

Returns: { "id": string, "name": string, "type": "segment", "parameters": object }

Examples:

  • "Mobile visitors" -> filters=[{dimension:'device', value:'mobile'}]

  • "Paid social, not from the US" -> filters=[{dimension:'utmMedium', value:'paid'}, {dimension:'country', value:'US', is_not:true}], match='all'

umami_create_cohortA

Create a persisted audience Cohort (visitors who performed an action within a date range, optionally filtered further) that appears under Audience > Cohorts in the Umami UI.

Args:

  • website (string, optional): Website ID, name, or domain.

  • name (string, required): Display name for the cohort.

  • action_type ('path' | 'event', required): Whether the qualifying action is a page view or a custom event.

  • action_value (string, required): The page path (e.g. '/audit') or event name (e.g. 'signup').

  • date_range ('7day'|'30day'|'90day'|'6month'|'12month'): Window the action must fall in, default '30day'.

  • filters (array, optional): Additional filters, each { dimension, value, is_not? }.

  • match ('all' | 'any'): Whether every filter must match, or just one (default: 'all').

Returns: { "id": string, "name": string, "type": "cohort", "parameters": object }

Examples:

  • "Visitors who viewed /audit in the last 30 days" -> action_type='path', action_value='/audit'

  • "Mobile visitors who fired 'signup' in the last 90 days" -> action_type='event', action_value='signup', date_range='90day', filters=[{dimension:'device', value:'mobile'}]

umami_list_segments_cohortsA

List the saved Segments or Cohorts for a website, as they appear under Audience in the Umami UI.

Args:

  • website (string, optional): Website ID, name, or domain.

  • type ('segment' | 'cohort', required): Which kind to list.

  • response_format ('markdown' | 'json'): Output format (default: 'markdown').

Returns: JSON shape: { "reports": [ { "id": string, "name": string, "type": string, "parameters": object, "created_at": string } ] }

umami_delete_segment_cohortA

Permanently delete a saved Segment or Cohort so it no longer appears in the Umami UI. Get the ID from umami_list_segments_cohorts.

This cannot be undone. Requires confirm=true.

Args:

  • website (string, optional): Website ID, name, or domain.

  • report_id (string, required): The segment/cohort's ID.

  • confirm (boolean, required): Must be true. There is no undo.

Returns: { "ok": true, "report_id": string }

umami_api_getA

Make a read-only GET request against any Umami API endpoint that does not have a dedicated tool here.

Use this only as a fallback. The dedicated tools handle date parsing, website resolution, and formatting; this one does not. It is the right choice for endpoints such as /websites/:id/sessions/weekly, /websites/:id/session-data/properties, /websites/:id/session-data/values, /reports, /teams, /me, and anything added in a newer Umami release.

Timestamps in params must be epoch milliseconds, and website IDs must be UUIDs. Only GET is permitted, so this tool cannot create, update, or delete anything.

Args:

  • path (string, required): API path relative to the API root, for example '/websites/abc-123/sessions/weekly'. Do not include the /api prefix or the host.

  • params (object, optional): Query string parameters as string values, for example { startAt: '1735689600000', endAt: '1738368000000', timezone: 'America/New_York' }.

Returns: The raw JSON response from Umami, pretty-printed.

Examples:

  • Weekly session heatmap: path="/websites//sessions/weekly", params={ startAt: "...", endAt: "...", timezone: "America/New_York" }

  • Session property names: path="/websites//session-data/properties", params={ startAt: "...", endAt: "..." }

  • Current user: path="/me"

Error handling:

  • Rejects any path containing a query string; put parameters in 'params' instead.

  • Returns the Umami status code and path on failure, so a 404 usually means the endpoint does not exist on this Umami version.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.1/5.0

Scored across 48 tools

Disambiguation5/5

Every tool targets a distinct resource+action pair, and potentially confusing pairs are explicitly cross-referenced (e.g. umami_get_goal vs umami_create_goal, umami_reset_website vs umami_delete_website, umami_list_saved_reports vs umami_list_segments_cohorts). Descriptions consistently explain when to prefer one tool over an overlapping alternative, so an agent can reliably select the right one.

Naming Consistency4/5

The dominant umami_<verb>_<noun> pattern in snake_case is followed by the vast majority of tools (list/get/create/update/delete/reset/join/add/remove). Minor deviations exist: umami_traffic_report lacks a verb, and umami_api_get reverses the pattern to noun_verb, but these are isolated and still readable.

Tool Count3/5

48 tools is heavy and pushes well beyond the 15-25 range where a tool set starts to feel bloated. However, the surface genuinely spans websites, teams, users, core analytics, replays, derived analytics, and persisted reports, so most tools earn their place; the count is defensible but will strain agent navigation.

Completeness4/5

The domain is covered impressively: full CRUD for websites/teams/users, comprehensive analytics querying, replay inspection, computed conversion/funnel/journey/retention/revenue analytics, and persistence for goals, funnels, segments, and cohorts, plus a read-only API fallback. Notable gaps remain: websites cannot be moved between teams (yet umami_delete_team tells you to reassign them first), and saved reports/segments/cohorts have no update path.

Maintenance

ActivityMaintained
ResponsivenessNo issues