Skip to content

fix(amplitude): correct wire formats and add funnels/retention analytics#5355

Open
waleedlatif1 wants to merge 5 commits into
stagingfrom
worktree-amplitude-validate
Open

fix(amplitude): correct wire formats and add funnels/retention analytics#5355
waleedlatif1 wants to merge 5 commits into
stagingfrom
worktree-amplitude-validate

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Fixed Identify/Group Identify APIs sending JSON instead of the form-urlencoded body Amplitude requires
  • Fixed Send Event sending snake_case product_id/revenue_type instead of Amplitude's camelCase productId/revenueType
  • Fixed Get Revenue parsing a response shape that never matched the real Revenue LTV API (was always returning empty data)
  • Added EU data residency support across all tools (EU projects were silently rejected by the US-only hosts)
  • Added missing filters/formula/segment params to Event Segmentation, groupBy/segment to Active Users and Revenue
  • Added first_used/last_used to User Activity output, non_active/flow_hidden to List Events output
  • Added real-time/hourly interval options to Event Segmentation
  • Added new Funnels and Retention tools for conversion and retention analysis
  • Updated brand colors to current Amplitude guide

Type of Change

  • Bug fix
  • New feature

Testing

Verified every fix against Amplitude's live API docs with 3 independent verification passes (wire format, response shape, block/tool alignment, backwards compatibility). bun run lint and tsc --noEmit both clean.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

- Fix Identify/Group Identify APIs sending JSON instead of required form-urlencoded bodies
- Fix Send Event using snake_case productId/revenueType instead of Amplitude's camelCase fields
- Fix Get Revenue parsing a response shape that doesn't match the real Revenue LTV API
- Add EU data residency support across all tools (Amplitude rejects EU projects on the US host)
- Add missing filters/formula/segment params to Event Segmentation, group-by/segment to Active Users and Revenue
- Add first_used/last_used to User Activity and non_active/flow_hidden to List Events
- Add real-time/hourly interval options to Event Segmentation
- Add Funnels and Retention tools for conversion and retention analysis
@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 2, 2026 7:30am

Request Review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches event ingestion and analytics API contracts; fixes change behavior for existing workflows (identify, revenue parsing, send-event fields), while new tools and EU routing are additive with default US behavior.

Overview
Fixes Amplitude integration bugs and expands analytics coverage so EU projects and several APIs work as documented.

API correctness: Identify and Group Identify now POST application/x-www-form-urlencoded bodies with stringified identification (replacing JSON). Send Event uses camelCase productId / revenueType on the event payload. Get Revenue output drops the incorrect xValues shape and types series as the LTV {dates, values} structure the API returns.

EU data residency: New getIngestionHost / getDashboardHost helpers route ingestion and dashboard calls to US or EU hosts; an advanced Data Residency block field (hidden for US-only User Profile) threads through tools.

New & extended analytics: Funnels and Retention operations, tools, registry entries, block UI, outputs (funnels), and a conversion-funnel skill template. Event Segmentation gains filters, formula, segment, and real-time/hourly intervals; Active Users and Revenue gain groupBy / segment. User Activity adds firstUsed / lastUsed; List Events adds nonActive / flowHidden.

Other: Block brand colors updated; User Profile description notes EU unavailability.

Reviewed by Cursor Bugbot for commit f60b057. Configure here.

Comment thread apps/sim/tools/amplitude/funnels.ts
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes four wire-format bugs in the existing Amplitude tools (form-urlencoded body for Identify/Group Identify, camelCase productId/revenueType in Send Event, corrected Revenue LTV response parsing) and adds EU data residency support, new funnels and retention analytics tools, and several missing query parameters across existing tools.

  • Bug fixes: identify_user and group_identify now send application/x-www-form-urlencoded bodies with a JSON-serialized identification array, matching what Amplitude's API requires; send_event now correctly sends productId/revenueType (camelCase); the get_revenue response parser now reflects the real Revenue LTV API shape (series objects with dates+values instead of flat arrays with an xValues key).
  • EU data residency: A new utils.ts provides getIngestionHost/getDashboardHost helpers; all tools except user_profile (US-only by Amplitude) now route EU projects to api.eu.amplitude.com / analytics.eu.amplitude.com.
  • New tools: amplitude_funnels validates the required events JSON array before URL construction and amplitude_retention validates startEvent/returnEvent as JSON objects, both throwing descriptive errors on malformed input — consistent with the filters validation pattern already applied to event segmentation.

Confidence Score: 5/5

Safe to merge — all changed code paths have been verified against Amplitude's API contracts and the framework's request-body handling.

The wire-format fixes (form-urlencoded bodies, camelCase revenue fields, corrected Revenue LTV response shape) are straightforward and align with Amplitude's documented API. The EU residency routing is handled by a clean utility function used consistently across every affected tool. The two new tools (funnels, retention) both validate required JSON params with descriptive errors before building the URL, matching the pattern established for filters in event_segmentation. The block config correctly forwards dataResidency through the executor's spread merge, and the config.params mappings for the new operations are complete. No silent-failure paths were introduced.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/tools/amplitude/utils.ts New utility module providing EU/US host selectors for ingestion and dashboard APIs; clean and correct.
apps/sim/tools/amplitude/identify_user.ts Fixes Content-Type to application/x-www-form-urlencoded and reformats body as URLSearchParams with JSON-serialized identification array; correctly handled by the framework's isPreformattedContent path.
apps/sim/tools/amplitude/group_identify.ts Same form-urlencoded wire-format fix as identify_user; EU host routing added; looks correct.
apps/sim/tools/amplitude/send_event.ts Corrects product_id/revenue_type to productId/revenueType and adds EU ingestion host support; fix is straightforward and correct.
apps/sim/tools/amplitude/funnels.ts New funnel analysis tool; validates events JSON array with descriptive errors, uses searchParams.append for multi-step e params, clean transformResponse.
apps/sim/tools/amplitude/retention.ts New retention analysis tool; validates startEvent/returnEvent as JSON objects, correctly maps Amplitude's se/re/rm/rb/i query params.
apps/sim/tools/amplitude/get_revenue.ts Fixes response parsing to match the real Revenue LTV API shape; xValues removed (was always empty), series type updated to reflect dates+values structure.
apps/sim/blocks/blocks/amplitude.ts Block config adds EU residency dropdown, funnels/retention operations with full param definitions, and correctly wires new params through config.params.
apps/sim/tools/amplitude/event_segmentation.ts Adds filters (with JSON validation and descriptive error), formula, and segment params; EU host routing added.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Block UI
    participant Exec as GenericBlockHandler
    participant Tool as Tool
    participant US as api2.amplitude.com
    participant EU as api.eu.amplitude.com

    UI->>Exec: block.config.params (all UI values incl. dataResidency)
    Exec->>Exec: config.params(inputs) → transformedParams
    Exec->>Exec: "finalInputs = {...inputs, ...transformedParams}"
    Exec->>Tool: executeTool(finalInputs)

    alt identify_user / group_identify
        Tool->>Tool: URLSearchParams body (form-urlencoded)
    else send_event
        Tool->>Tool: JSON body (productId, revenueType)
    else funnels
        Tool->>Tool: "Validate events array, append ?e= per step"
    else retention
        Tool->>Tool: Validate startEvent/returnEvent as JSON objects
    end

    alt "dataResidency == eu"
        Tool->>EU: GET/POST request
        EU-->>Tool: Response
    else "dataResidency == us (default)"
        Tool->>US: GET/POST request
        US-->>Tool: Response
    end

    Tool-->>Exec: ToolResponse
    Exec-->>UI: block output
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Block UI
    participant Exec as GenericBlockHandler
    participant Tool as Tool
    participant US as api2.amplitude.com
    participant EU as api.eu.amplitude.com

    UI->>Exec: block.config.params (all UI values incl. dataResidency)
    Exec->>Exec: config.params(inputs) → transformedParams
    Exec->>Exec: "finalInputs = {...inputs, ...transformedParams}"
    Exec->>Tool: executeTool(finalInputs)

    alt identify_user / group_identify
        Tool->>Tool: URLSearchParams body (form-urlencoded)
    else send_event
        Tool->>Tool: JSON body (productId, revenueType)
    else funnels
        Tool->>Tool: "Validate events array, append ?e= per step"
    else retention
        Tool->>Tool: Validate startEvent/returnEvent as JSON objects
    end

    alt "dataResidency == eu"
        Tool->>EU: GET/POST request
        EU-->>Tool: Response
    else "dataResidency == us (default)"
        Tool->>US: GET/POST request
        US-->>Tool: Response
    end

    Tool-->>Exec: ToolResponse
    Exec-->>UI: block output
Loading

Reviews (5): Last reviewed commit: "fix(amplitude): tighten JSON shape valid..." | Re-trigger Greptile

Comment thread apps/sim/tools/amplitude/funnels.ts
- Guard against non-array/non-object JSON in the funnel steps param instead of crashing on for...of
- Throw a descriptive error instead of silently sending an empty funnel when the JSON is unparseable
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/amplitude/funnels.ts
Throw a descriptive error when the parsed events JSON yields zero valid step objects instead of silently sending a funnel request with no steps.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/amplitude/event_segmentation.ts
Comment thread apps/sim/tools/amplitude/funnels.ts
…tial funnel steps

- Event Segmentation now throws on invalid filters JSON instead of silently running unfiltered
- Funnels now rejects the request when any parsed step isn't a valid object instead of silently dropping it and sending a shorter funnel
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/amplitude/funnels.ts
Comment thread apps/sim/tools/amplitude/funnels.ts Outdated
Comment thread apps/sim/tools/amplitude/funnels.ts
Comment thread apps/sim/tools/amplitude/event_segmentation.ts
Comment thread apps/sim/tools/amplitude/retention.ts Outdated
…n/retention

- Funnels: require a strict JSON array of plain objects (reject nested arrays as steps, reject single-object leniency), and guard transformResponse against a non-array data.data
- Event Segmentation: require filters to parse to an array, not just any JSON value
- Retention: validate startEvent/returnEvent parse to plain JSON objects before sending, matching the funnels/segmentation precedent
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f60b057. Configure here.

Comment thread apps/sim/blocks/blocks/amplitude.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant