MCP App Store
Data
Polar Analytics icon

Polar Analytics

by Polar Analytics

Overview

Polar is the trusted data layer for commerce brands. Connect your Shopify, Meta, Google, Klaviyo, and 45+ other data sources into a unified semantic layer with validated metrics, custom business rules, and cross-platform attribution. Turn Claude into your data analyst. Get answers on ROAS, CAC, top-performing SKUs, profit margins, and more, with answers grounded in consistent, reconciled data instead of raw API pulls. Polar eliminates the "different answer every time" problem by applying your business definitions, exclusions, and attribution logic to every query. Supports multi-store setups and works with major e-commerce integrations.

Tools

create_custom_dimension

ChatGPT
Create a new custom dimension for this tenant. A custom dimension is a rule-based (when/then/else) label derived from existing dimensions. Prefer reusing an existing custom dimension. Before calling this tool, inspect the custom_dimensions field returned by get_context and, if needed, fetch details via get_custom_dimension_details. Only create a new one if no existing dimension matches the user's intent semantically. ===== json payload shape (CustomDimension) ===== { "whenThen": [ { "when": [ WhenBlock, ... ], "then": [ "<label>" ] // array of bare strings }, ... ], "else": [ "<fallback label>" ] // array of bare strings } WhenBlock = { "lineOperator": "" | "and" | "or", // Trailing connector — joins this block to the NEXT one. // Last block always "". For multi-block whens, the first // and middle blocks carry "and"/"or"; only the final one is "". "leftValue": [ "dimension.<table>.<field>" ], // array, one entry "operator": "is" | "isNot" | "isInList" | "isNotInList" | "contains" | "notContains" | "containsCaseSensitive" | "notContainsCaseSensitive" | "startsWith" | "endsWith" | "lower" | "lowerOrEqual" | "greater" | "greaterOrEqual" | "isBefore" | "isAfter" | "isNull" | "isNotNull" | "isEmpty" | "isNotEmpty", "value": "<string>" // for isInList / isNotInList use a // comma-joined string: "US,CA,MX" } Required inputs: - conversation_id - title (short, human-readable name) - json (per the shape above) On success returns { id, title, editUrl }. The chat UI surfaces the editUrl as an "Open dimension editor" button on the tool-call card — do NOT repeat it as a markdown link in your visible response. Just tell the user the dimension was created and briefly describe what it groups.

create_custom_metric

ChatGPT
Create a new custom metric for this tenant. A custom metric is a formula built from a sequence of elements (existing metric refs, operators, values). Prefer reusing an existing metric. Call get_metrics first with custom-metrics included to see what already exists; only create if no existing metric matches the user's intent semantically. Aggregation note: the formula is evaluated per-row then SUMmed at the outer query level (ratio-of-SUM for simple arithmetic). For division on same-source metrics the aggregation becomes SUM-of-ratio, which can surprise the user on multi-day granularity. ===== metricData payload shape ===== Required: title, elements, formatting. description is optional. elements: array of typed-object nodes. Every element is an OBJECT, never a bare string. Valid shapes: - Metric reference: { "type": "metric", "value": "<table>.raw.<key>" // e.g. shopify_sales_main.raw.gross_sales | "<table>.computed.<key>" | "custom_<N>", "filters": [] // optional; omit or [] // when no filters apply } - Arithmetic operator: { "type": "operator", "value": "+" | "-" | "*" | "/" | "(" | ")" | "x" } - Literal value (numeric constant inside the formula): { "type": "value", "value": "<number-as-string>" } // e.g. "2" - Line break (visual only, rare): { "type": "linebreak", "value": "" } Filters on a metric element (optional). Each filter is one of: - OR element: { "dimension": "<dimKey>", "operator": "IS" | "ISNOT" | "CONTAINS" | "NOTCONTAINS", "values": ["a","b"] } - AND group: an array of the OR elements above Empty array or omitted field = "no filter on this metric ref". formatting: REQUIRED object, one of four discriminated shapes: - { "type": "number", "numberType": "integer" | "decimal", "prefix"?: string, "suffix"?: string, "metricRepresentation"?: "higher_is_better" | "lower_is_better" } - { "type": "percent", "metricRepresentation"?: "higher_is_better" | "lower_is_better" } - { "type": "currency", "currency"?: string, // 3-letter ISO "metricRepresentation"?: "higher_is_better" | "lower_is_better" } - { "type": "timedelta", "metricRepresentation"?: "higher_is_better" | "lower_is_better" } Required inputs: - conversation_id - metricData (per shape above) On success returns { id, title, editUrl }. The chat UI surfaces the editUrl as an "Open metric editor" button on the tool-call card — do NOT repeat it as a markdown link in your visible response. Just tell the user the metric was created and briefly describe what it computes.

delete_custom_dimension

ChatGPT
Delete an existing custom dimension. Deletion is permanent (hard delete); only the MCP audit log retains the payload for recovery. CRITICAL (non-self-created items): If you did NOT create this dimension in the current conversation, BEFORE calling this tool you MUST: 1. Call get_custom_dimension_usages to see what depends on it. If non-empty, tell the user in plain English what would be orphaned (names + types, not just counts) and stop — deletion is blocked anyway, so don't try. 2. If the usages list is empty, tell the user the dimension's name (and id, for reference) and ask whether to proceed with deletion. 3. Once the user gives a clear affirmation ("yes", "go ahead", "delete it", etc.), call this tool. You do NOT need the user to repeat the id. For items you created in the CURRENT conversation: delete freely when asked. The server also runs an in-use check; if any references exist it returns a blockedBy list. Relay that list to the user and stop — do not cascade or work around the block. Required inputs: - conversation_id - id (the custom_<N> id)

delete_custom_metric

ChatGPT
Delete an existing custom metric. Deletion is permanent (hard delete); only the MCP audit log retains the payload for recovery. CRITICAL (non-self-created items): If you did NOT create this metric in the current conversation, BEFORE calling this tool you MUST: 1. Call get_custom_metric_usages to see what depends on it. If non-empty, tell the user in plain English what would be orphaned (names + types, not just counts) and stop — deletion is blocked anyway, so don't try. 2. If the usages list is empty, tell the user the metric's name (and id, for reference) and ask whether to proceed with deletion. 3. Once the user gives a clear affirmation ("yes", "go ahead", "delete it", etc.), call this tool. You do NOT need the user to repeat the id. For items you created in the CURRENT conversation: delete freely when asked. The server also runs an in-use check; if any references exist it returns a blockedBy list. Relay that list to the user and stop — do not cascade or work around the block. Required inputs: - conversation_id - id (the custom_<N> id)

generate_report

ChatGPT
Generate a comprehensive analytics report. Required inputs: - conversation_id, - metrics (comma-separated keys exactly as received from the metrics field of the get_context tool), - dimensions (comma-separated keys exactly as received from the breakdowns field in list_dimensions), - dateRangeFrom/dateRangeTo (YYYY-MM-DD), - ordering (comma-separated key-value pairs of key and direction) - granularity (none|day|week|month|year), - settings (e.g. attribution model - pass empty object if non-attribution query) - rules (JSON string like {"country":[{"value":["US"],"operator":"IS"}]}), - metricRules (JSON string like {"shopify_sales_main.raw.total_orders":[{"operator":"GREATER","value":["0"]}]}), - views (comma-separated ids exactly as received from the view field of list_dimensions), - limit (optional, integer): Max rows to return (default 1000). ALWAYS set an explicit limit appropriate to the query — for browsing/listing choose a single integer between 10 and 25, for analysis use only as many rows as needed. Fetching too many rows wastes context. The full dataset is always available via the returned deep link. - comparisonPeriod (optional): Compare against a previous period. Values: previousPeriod (same duration before current range), previousYear, previousMonth, or range (requires comparisonDateRangeFrom/To). - comparisonDateRangeFrom/comparisonDateRangeTo (optional, YYYY-MM-DD): Custom comparison date range, only used when comparisonPeriod is "range". Output: JSON report table data, totals data and a deep link to display the same table (with totals) in-app. When comparison is requested, also returns compareTableData, compareTotalData, and comparisonDateRange. Only include attribution_model in settings when generating reports that involve marketing channel attribution or cross-channel analysis. For Shopify metrics (sales, orders, product data, customer segments), pass an empty settings object if you do not know the attribution model. Totals data: returns a row of totals for every metric in the metrics list. Always use these provided totals; do not recompute sums yourself unless you really need to. For grouped/segmented reports (e.g., “top 5 cities”), sum the returned rows and verify they never exceed the corresponding server totals; if there’s a mismatch, prefer the server totals and call it out as a reconciliation note. For ungrouped reports, display the returned totals directly. When presenting percentages or shares, compute them as row_value / total_value (not from independently summed rows) If a total is missing for a metric, state that totals are unavailable and avoid inferring them. When the data is useful, include the exact deep link so the customer can explore further on their own in-app. Use the 👉 emoji to make it very clear that it's a link. Use generate_app_report_link to generate other links or visualizations as needed. If you got the report from an element in the get_dashboard_details tool, use those deep links. This shouldn't prevent you from generating an artifact with other content if needed, the goal is for the user to link to the Polar report if they want to validate the data or explore further. After responding, ask user for a 1-10 rating, then call rate_report. Gating: this tool refuses with { error: true, reason: "needs_activation" | "needs_connectors", message, book_call_url, connectors_url } when account_status from get_context indicates the tenant is not yet activated or has no loaded connector data. Don't retry on the same tenant in the same conversation — deliver the message verbatim or paraphrase, point the user at the URL, and stop.

get_connector_statuses

ChatGPT
Detailed per-account connector health from /api/datasources/statuses. Use this to drill into the rollup returned by get_context.connectors when the user asks why a connector is Warning/Broken/Syncing history, or to compose remediation prose. Each entry is { key, health, connections, accounts[] }. connections is the per-status breakdown of this connector's accounts (sparse — absent keys mean zero). accounts[] carries { datasource_id, account_name, health, issues, last_completed_sync_at, data_available_through, timezone, data_integrity }. data_integrity is a rollup of the account's data integrity checks: { ok, failed, total } counts, or null when no check signal is available. "ok" includes both exact matches and within-tolerance results — both pass from the user's perspective. For the per-check breakdown (name, status, match rate, in/out-of-tolerance days), call get_data_integrity_report({ datasource_id }). health is one of: healthy | syncing_history | warning | broken | paused | pending. The connector-level health is the worst across its accounts (except all-paused → paused). issues[] is a structured array. Compose the prose yourself from the kind: - error: { kind: "error", message } — generic plumbing error surfaced verbatim from the connector - needs_setup: account is connected but no sub-account is selected; user should finish setup - missing_scopes: { kind: "missing_scopes", scopes } — the connector is missing OAuth scopes; user should reconnect granting these scopes - delayed: no sync today past the morning threshold in the connector's timezone; surface to the user. Hourly-refresh staleness is not flagged until the team calibrates a per-pipeline threshold. - drift_summary: { kind: "drift_summary", failed_count, tolerated_count, total_count } — at least one data integrity check failed (its match rate is below the threshold). Tell the user "X of Y checks failed" (the wording the data integrity report uses) and link to the report. tolerated_count is informational only; those days are within tolerance and the user sees them as "OK". - drift_verified: { kind: "drift_verified", tolerated_count, total_count } — every data integrity check passed (some may be within tolerance, which the user sees as "OK"); surface as positive reassurance, do not flag as a problem Never speculate about lag from last_completed_sync_at alone — only act on explicit issues[] entries. Deep-link pattern (do NOT slugify account names): /connectors/<connector-key> — connector page /connectors/<connector-key>/<datasource_id> — specific account row, where datasource_id is the UUID from accounts[].datasource_id /connectors/<connector-key>/<datasource_id>/data-integrity — data integrity report (full pass/fail breakdown + drill-down per check) Example: /connectors/facebook-ads/8f3a1c0e-44d6-4d8a-9f8b-7c2a1e5d9a40 Required input: conversation_id (from get_context). Optional: connectorKeys to narrow the response to a subset of connectors from get_context.connectors.

get_context

ChatGPT
Run this tool once at the beginning of each conversation to prepare the analytics environment. It returns a combined JSON object with five elements: conversation_id: Conversation ID context: Workspace context { currency, timezone, brand_name (if none is set, it defaults to the email of the first registered user, often the brand’s domain, sometimes a personal email) }; account_status: { activation: 'pending_call' | 'call_booked' | 'activated', data: 'none' | 'loading' | 'ready', book_call_url, connectors_url, message } describing whether the tenant is activated and whether their data is loaded. If activation is not 'activated', tell the user to book the setup call at book_call_url before doing anything else — booking is the highest-priority next step and data tools will refuse until activation completes. Otherwise, if data is not 'ready', tell the user to connect data sources at connectors_url. The 'message' field is a ready-to-deliver explanation; surface it verbatim or paraphrase, but always include the relevant URL. When account_status.message is non-empty, deliver it before any analytics work; connectors: Canonical per-connector rollup. Each entry { key, health, connections } where health is one of healthy | syncing_history | warning | broken | paused | pending (worst across accounts; all-paused → paused). connections is the per-status breakdown of this connector's accounts — only includes health states with at least one account, absent keys mean zero. Total account count = sum of connections values. When any connector is warning, broken, or syncing_history, mention it to the user and offer the deep link. Call get_connector_statuses to drill into specific connectors and compose remediation prose from the structured issues[]. polar-pixel appears in this list like any other connector — health syncing_history means it is still warming up; healthy means it has matured. Note: the canonical health currently only surfaces daily delay signals (no sync today past the morning threshold in the connector's timezone). Hourly-refresh staleness is not flagged until the team calibrates a per-pipeline threshold. Do not speculate about lag from last_completed_sync_at alone; act only on explicit issues[]. custom_connectors: Array of { key } for connectors that have queryable data tables but no live monitoring (custom imports, data warehouses, legacy entries). Treat their health as unknown — never claim they are healthy or broken. connector_status: DEPRECATED — superseded by 'connectors' and 'custom_connectors'. Kept only for backward compatibility and will be removed in a future MCP version. Prefer 'connectors' for health and 'get_connector_statuses' for detail. Legacy shape: array of { name, status, until } where status is 'historical' (data not ready), 'incremental' (data ready up to 'until'), or 'paused' (data exists but syncing is paused — reports use data up to 'until'). Customers can manage connectors at https://app.polaranalytics.com/connectors. If a polar-pixel legacy entry has is_warmed_up=false, the pixel needs attention. Open your final answer with a bold data-quality warning before any numbers. If installed_at is a date, say the pixel is still warming up (give installed_at as the install date) and conversion / attribution numbers aren't statistically meaningful yet — suggest letting it accumulate for at least a couple of weeks before drawing conclusions, with the actual time depending on traffic volume and industry. If installed_at is null, say the pipeline last produced data on polar-pixel 'until' and may not be currently flowing — numbers may be stale. Deep-link pattern for the Connectors area (use canonical 'connectors' key and accounts[].datasource_id from get_connector_statuses; never slugify account names): https://app.polaranalytics.com/connectors/<connector-key> for a connector page, https://app.polaranalytics.com/connectors/<connector-key>/<datasource_id> for an account row. Example: https://app.polaranalytics.com/connectors/facebook-ads/8f3a1c0e-44d6-4d8a-9f8b-7c2a1e5d9a40. custom_dimensions: Initial page of the te…

get_custom_dimension_details

ChatGPT
Used to discover what filtering a custom dimension does. Note: When the user is only looking to use the custom dimension and it's clear which custom dimension they're referring to, looking up its details is superflous. Required inputs: - conversation_id - id (the id of a custom dimension, exactly as obtained from the custom_dimensions field of get_context) Returns the custom dimension with its definition (rules and connector filters).

get_custom_dimension_usages

ChatGPT
List every tenant-owned object that currently depends on a given custom dimension — reports, custom metrics, and KI sections. MUST be called before any update_custom_dimension or delete_custom_dimension attempt on a dimension that was NOT created in the current conversation. Use the result to tell the user in plain English what the change would affect (e.g. "This dimension is used by 3 reports and 1 KI section — these are the names…") before asking for confirmation. Returns { usages: [{ id, title, type: "report" | "custom_metric" | "ki_section" }] }. An empty list means nothing currently depends on it. Required inputs: - conversation_id - id (the custom_<N> id of the dimension)

get_custom_metric_details

ChatGPT
Fetch the full formula of a single custom metric by id. Use when you've found a candidate custom metric via list_custom_metrics (or get_metrics) and need its elements + formatting to judge whether it matches the user's intent before using or extending it. Required inputs: - conversation_id - id (the custom_<N> id) Returns { id, label, description?, elements, formatting }.

get_custom_metric_usages

ChatGPT
List every tenant-owned object that currently depends on a given custom metric — reports, other custom metrics, and KI sections. MUST be called before any update_custom_metric or delete_custom_metric attempt on a metric that was NOT created in the current conversation. Use the result to tell the user in plain English what the change would affect (names, types, count) before asking for confirmation. Returns { usages: [{ id, title, type: "report" | "custom_metric" | "ki_section" }] }. An empty list means nothing currently depends on it. Required inputs: - conversation_id - id (the custom_<N> id of the metric)

get_dashboard_details

ChatGPT
Use this tool when a user references a specific report inside Polar. Retrieve the full definition of a single dashboard, including all its elements. Customers generally refer to the dashboards and/or elements by their titles. In order to get further details on a specific report, please use get_dashboard_details. Required inputs: - conversation_id Output: A single dashboard with the details of its elements, along with deep links. If a dashboard or a report has a deep link, always include that link when referring to the dashboard/report. The table data has a limit of 50 applied. More rows can be retrieved with the generate_report tool as needed. If the tenant is not yet activated or has no connector data loaded, this tool returns the dashboard structure (titles, layout, deep links) but skips the per-element data and includes data_skipped: true plus a reason and message from account_status in get_context. When you see data_skipped, deliver the message verbatim or paraphrase, point the user at the URL, and do not fabricate numbers.

get_data_integrity_report

ChatGPT
Per-check breakdown of the latest data integrity report run for a single account. This is the same report the user sees at /connectors/<connector-key>/<datasource_id>/data-integrity. Use it as the drill-in when get_connector_statuses returns a non-null data_integrity rollup on an account and the user asks for specifics (which check, its match rate, which dates were out of tolerance). Returns { tests: [{ name, status, errorRatio, matchedValues, unmatchedValues }] }. Each test is a "check" on the report. What drives a check's status is its overall match rate, not individual days. match rate = (1 - errorRatio), shown to the user as a percentage (e.g. errorRatio 0.109 → "89.1% match rate"). A check is marked Failed when its match rate is below the configured threshold; a single day out of tolerance does not fail the check on its own. Use "match rate" when talking to the user — that is the wording on the report. status values: - SUCCESS — matches the source exactly. The report shows this as "OK". - WITHIN_TOLERANCE — differs from the source but within the configured tolerance. The report also shows this as "OK" (no distinction from SUCCESS on the public surface). - FAILED — the match rate is below the threshold. The report shows this as "Failed". - SKIPPED — the check did not run for this account. - ERROR — the check could not execute (e.g. API call failed). A check that ran but had zero days to compare (both matchedValues and unmatchedValues empty) is shown as "No data" on the report; describe it that way instead of OK or Failed. errorRatio is the magnitude of mismatch as a fraction of expected (0 = exact match); the report surfaces its inverse as the match rate. matchedValues and unmatchedValues are per-day breakdowns keyed by date with { expected, current } pairs (numbers, or "No value" when the source returned nothing for that day). On the report each matched day is labeled "In tolerance" and each unmatched day "Out of tolerance". Only the latest incremental run is returned. Historical runs are not surfaced. Required input: conversation_id and datasource_id (the UUID from get_connector_statuses accounts[].datasource_id).

get_dimension_values

ChatGPT
Get the possible values for a given dimension. Inputs: - dimension: required. The dimension to get the values for. - tables: required. The tables to get the values from, as an array of strings. - search: optional. The search text to filter the values. If set, only the values containing the search text will be returned. Returns a JSON array with the possible values for the dimension, up to a maximum of 100 values.

get_metrics

ChatGPT
List the metrics available for a list of sources. Connector metrics are returned as { key, label }. Custom metrics carry { key, label } plus ONE of: - summary: human-readable one-line purpose (preferred when authored or AI-summarized) - refs: array of underlying metric labels the formula touches. Use as a structural hint when no summary exists — a clumsy label like "ROAS v2 jamie" with refs ["Total ad spend", "Net sales"] is very likely a return-on-ad-spend metric. Match on label + summary + refs together when judging whether an existing custom metric already covers the user's intent. Use the exact 'key' values in other tools—do not modify them. If you are unsure which metric to use, ask the user to confirm. The full elements + filters formula is NOT inlined; call get_custom_metric_details(id) to fetch the full body for any candidate worth inspecting. The custom-metrics list is capped at the 300 most recently created/updated custom metrics. For older or oddly-named metrics beyond this initial set, call list_custom_metrics(q?, offset?, limit?) — paginated + searchable by case-insensitive substring on title and summary. If the user references a metric by name and you don't see it here, search via list_custom_metrics before creating a duplicate. SOURCES: A source is either a connector name (from connector_status) or 'custom-metrics'. IMPORTANT: Include 'custom-metrics' in your first call to discover custom metrics for the conversation. Custom metrics contain critical business logic that the user expects you to know about. Omitting them risks ignoring user-defined metrics and giving incorrect answers. SOURCE SELECTION RULES: 1. If the user names a data source (e.g., "Google Analytics", "GA4", "Shopify", "Facebook Ads", "Meta"), include the matching connector key from connector_status. Map common phrasing to the exact connector key: - "GA4", "Google Analytics", "Google Analytics 4" → google-analytics-four - "Facebook", "Facebook Ads", "Meta", "Meta Ads" → facebook-ads - "Google Ads", "Adwords" → google-ads - "Shopify" → shopify - "TikTok", "TikTok Ads" → tiktok-ads - "Klaviyo" → klaviyo - "Polar Pixel", "Pixel" → polar-pixel When in doubt, match case-insensitively against the name field in connector_status. 2. If the question spans multiple sources (e.g., "compare Shopify revenue to Facebook spend"), include ALL referenced connectors. 3. If the scope is ambiguous, include every connector that could plausibly answer the question — do not default to one connector. It is better to over-include relevant connectors than to miss the one the user cares about. 4. Always include 'custom-metrics' on the first call. EXAMPLES: - User: "look at google analytics four landing page data" → sourceList: "google-analytics-four,custom-metrics" - User: "Shopify revenue last 30 days" → sourceList: "shopify,custom-metrics" - User: "blended ROAS this month" → sourceList: every ad-platform connector + shopify + custom-metrics - User: "how is my business doing" → sourceList: every connector in connector_status + custom-metrics CRITICAL: Custom metrics (keys starting with 'custom_') contain USER-DEFINED business logic specific to this account. MANDATORY RULE: When a user requests a metric by name or concept: - Search the custom metrics list FIRST for matching labels - If a custom metric matches the user's request, you MUST use it - Standard metrics are ONLY used when no relevant custom metric exists - Using a standard metric when a custom version exists is an ERROR. - Before calling create_custom_metric, verify via this list (and via list_custom_metrics for the long tail) that no existing custom metric already captures what the user wants — prefer reusing an existing metric and cite it by label in your response. METRIC KEY ARCHITECTURE: Metric keys follow different patterns based on their scope: - Table-specific metrics have table prefixes: shopify_sales_main.raw.*, shopify_sales_main.computed.*, facebook_ads_main.raw.* - Blended metrics have NO table prefix (e.g., polar_pixel_conversion_rate, blended_roas, `pi…

get_view_details

ChatGPT
Used to discover what a view (a segment/set of dimensions pre-configured by the user) does. Note: When the user is only looking to use the view and it's clear which view they're referring to, looking up its details is superflous. Required inputs: - conversation_id - view (the id of a view, exactly as obtained from the view field of get_context) Returns the view with its definition (rules and connector filters).

list_custom_dimensions

ChatGPT
Browse or search the tenant's custom dimensions beyond the first page surfaced by get_context. Sorted by recency-of-update (most recently edited / created first). Pass q to filter by case-insensitive substring on title or summary; omit q to page through everything. USE THIS WHEN: - The user references a custom dimension by name and you don't see it in the get_context list. - You're about to call create_custom_dimension and want to double-check no existing dimension covers the same intent. - You need to enumerate dimensions that touch a particular underlying field (search by the field name as a query — e.g. q="country" surfaces every dimension whose label or summary mentions country). Returns { items: [{ id, label, summary?, refs? }], total, offset, limit, hasMore }. Each item carries the same compact shape as get_context's custom_dimensions slot. Call get_custom_dimension_details(id) to fetch the full whenThen formula for any candidate that looks worth inspecting. Required inputs: - conversation_id Optional inputs: - q (case-insensitive substring; matches title or summary) - offset (default 0) - limit (default 50, max 200)

list_custom_metrics

ChatGPT
Browse or search the tenant's custom metrics. Sorted by recency-of-update (most recently edited / created first). Pass q to filter by case-insensitive substring on title or description; omit q to page through everything. USE THIS WHEN: - The user references a custom metric by name and you don't see it in get_metrics's custom-metrics output. - You're about to call create_custom_metric and want to double-check no existing metric covers the same intent. Returns { items: [{ id, label, summary?, refs? }], total, offset, limit, hasMore }. refs lists the underlying metric keys that the custom metric's formula depends on. The full elements formula is not inlined; the get_metrics tool already returns it for items in the standard custom-metrics page. Required inputs: - conversation_id Optional inputs: - q (case-insensitive substring; matches title or description) - offset (default 0) - limit (default 50, max 200)

list_dashboards

ChatGPT
When a user references a dashboard or report by name, call list_dashboards first to verify existence before generating data. A dashboard is a core building block in the Polar platform. Supported dashboard elements include reports (tables, charts etc.) and key indicator sections (i.e. metric grids). Customers generally refer to the dashboards and/or elements by their titles. In order to get further details on a specific report, please use get_dashboard_details. Required inputs: - conversation_id Output: A list of dashboards and their elements, along with deep links. If a dashboard or a report has a deep link, always include that link when referring to the dashboard/report.

list_dimensions

ChatGPT
Given comma-separated metric names from get_context, return compatible breakdowns, filters and settings. Note: all metrics can use the 'date' dimension, so you do not need to check for it. You need to do this for each new set of metrics, as it can vary greatly. IMPORTANT: If the user explicitly requested a specific breakdown (e.g. "by landing page", "per product") and it does NOT appear in the breakdowns response, your chosen metrics are incompatible with that dimension. Do NOT silently switch to a different breakdown. Instead, call list_metrics_for_dimension with the user's requested dimension to find compatible metrics, then retry with those. Required inputs: - conversation_id Returns a JSON object with three keys: - breakdowns (dimensions that the supplied metrics can be grouped by) - filters (dimensions that the supplied metrics can be filtered by) - settings (key value pairs of settings and possible values) Example: { "attribution_model": [ { "value": "last_click", "label": "Last Click" }, { "value": "linear", "label": "Linear" }, ] If you are looking for a given dimension and you are not sure which one you should use, you need to ask confirmation to the user. Generally, the user do not want to breakdown by IDs, they want to breakdown by names, or titles. Example: sales_channel_name instead of sales_channel. You can use the get_dimension_values tool to get the possible values for some dimensions and figure out which one you should use. CRITICAL: Custom dimensions (keys starting with 'custom_') contain USER-DEFINED business logic specific to this account. MANDATORY RULE: When a user requests a dimension by name or concept: - Search the custom dimension list FIRST for matching labels - If a custom dimension matches the user's request, you MUST use it - Standard dimensions are ONLY used when no relevant custom dimensions exists - Using a standard dimension when a custom version exists is an ERROR. This rule does NOT apply to custom_default dimensions.

list_metrics_for_dimension

ChatGPT
Given a dimension key, return metrics that are likely to support it as a breakdown. Use this tool BEFORE picking metrics when the user names a specific breakdown (e.g., "by landing page", "per product"). STRICT RULE: When calling generate_report with this breakdown, use ONLY metrics returned by this tool. Do NOT add metrics from get_metrics — not even computed ones from the same table. A single unsupported metric will cause the breakdown to fail with "cannot apply breakdown by <dimension>". If you want more metric variety, run a second report without the breakdown. Required inputs: - conversation_id - dimension (a single dimension key as it appears in the breakdowns field of list_dimensions) Returns an array of { key, label } metrics. Returns an empty array if the dimension does not exist or no metrics support it. Known gaps: this tool does not yet include blended metrics (no table prefix) or custom metrics (keys starting with custom_). If the user needs those with a breakdown, verify compatibility via list_dimensions.

rate_report

ChatGPT
Submit the user's rating for your previous analysis. ONLY call this after the user explicitly provides a rating. Do not rate yourself. Inputs: - rate (string number 1-10), - reflexion (your analysis of their goal and why they are rating it this way). Output: confirmation message.

update_custom_dimension

ChatGPT
Update an existing custom dimension. CRITICAL (non-self-created items): If you did NOT create this dimension in the current conversation, BEFORE calling this tool you MUST: 1. Call get_custom_dimension_usages with the dimension's id to discover exactly what depends on it. 2. In plain English, tell the user: - the dimension's name (and id, for reference) - what the proposed change is - which downstream objects would be affected — names and types (reports, custom metrics, KI sections), not just counts - that the change will apply immediately to those objects 3. Ask whether to proceed. 4. Once the user gives a clear affirmation ("yes", "go ahead", "do it", "update it", etc.), set userConfirmedInChat: true and call this tool. You do NOT need the user to repeat the id — they already know which item you mean from your previous message. For items you created in the CURRENT conversation: low risk, proceed without the usages lookup. Still set userConfirmedInChat: true (the flag protects the write path regardless). See create_custom_dimension for the full CustomDimension payload shape. Required inputs: - conversation_id - id (the custom_<N> id exactly as surfaced by get_context) - title (new title) - json (per the shape above) - userConfirmedInChat (must be true) On success returns { id, title, editUrl }. The chat UI surfaces the editUrl as an "Open dimension editor" button — do NOT repeat it as a markdown link in your visible response.

update_custom_metric

ChatGPT
Update an existing custom metric. CRITICAL (non-self-created items): If you did NOT create this metric in the current conversation, BEFORE calling this tool you MUST: 1. Call get_custom_metric_usages with the metric's id to discover exactly what depends on it. 2. In plain English, tell the user: - the metric's name (and id, for reference) - what the proposed change is - which downstream objects would be affected — names and types (reports, other custom metrics, KI sections), not just counts - that the change will apply immediately to those objects 3. Ask whether to proceed. 4. Once the user gives a clear affirmation ("yes", "go ahead", "do it", "update it", etc.), set userConfirmedInChat: true and call this tool. You do NOT need the user to repeat the id — they already know which item you mean from your previous message. For items you created in the CURRENT conversation: low risk, proceed without the usages lookup. Still set userConfirmedInChat: true. The server will additionally reject the update if existing reports would become incompatible — that is an extra safeguard, not a substitute for your caution. See create_custom_metric for the full metricData payload shape. Required inputs: - conversation_id - id (the custom_<N> id) - metricData (full replacement CustomMetric payload) - userConfirmedInChat (must be true) On success returns { id, title, editUrl }. The chat UI surfaces the editUrl as an "Open metric editor" button — do NOT repeat it as a markdown link in your visible response.

generate_report

Claude

get_context

Claude

get_custom_dimension_details

Claude

get_dashboard_details

Claude

get_dimension_values

Claude

get_metrics

Claude

get_view_details

Claude

list_dashboards

Claude

list_dimensions

Claude

rate_report

Claude

App Stats

36

Tools

ChatGPT, Claude

Platforms

Works with

ChatGPT
Claude

Data refreshed daily