# How to Integrate Retool with FullStory

- Tool: Retool
- Difficulty: Intermediate
- Time required: 25 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to FullStory by creating a REST API Resource with FullStory's API endpoint and API key authentication. Pull session recordings, user events, and frustration signals into support dashboards — giving your team direct access to session replay links alongside internal user records, so they can instantly understand what users experienced before submitting support tickets.

## Build a Support Panel That Surfaces FullStory Session Data in Retool

FullStory captures everything users do on your product — every click, scroll, form interaction, and navigation event. When a user submits a support ticket, your support agents typically have to ask 'what were you doing when this happened?' and wait for a vague answer. With FullStory connected to Retool, agents can look up the user's recent sessions and watch exactly what happened before the ticket was created.

Retool is the ideal integration layer for FullStory because it lets you combine FullStory's session data with your internal records in a single panel. An agent can search by user email, see their FullStory session list, click a link to open the replay directly in FullStory, and see frustration signals (rage clicks, error clicks) that FullStory detected — all alongside the user's account data and ticket history from your own database.

FullStory's API gives access to users, sessions, and events. The most useful data for support workflows is the sessions list (to find the relevant recording) and the events stream (to understand what happened in-session). FullStory's API returns direct replay URLs that link back to the FullStory player — your team clicks the link in Retool and watches the session in FullStory without any additional configuration.

## Before you start

- A FullStory account with API access enabled (FullStory Business plan or higher)
- A FullStory API key (Admin → Account Settings → Integrations → FullStory API)
- A Retool account with permission to create Resources
- Your FullStory org ID (visible in your FullStory URL or account settings)
- Optional: internal user database to join with FullStory user IDs for enriched support panels

## Step-by-step guide

### 1. Create a FullStory REST API Resource in Retool

Navigate to the Resources tab in Retool and click Add Resource. Select REST API from the list. Name the resource 'FullStory API'.

In the Base URL field, enter https://api.fullstory.com. This is FullStory's REST API base URL. All endpoint paths will be appended to this base.

In the Authentication section, select Bearer Token. In the Token field, enter your FullStory API key. To keep the key secure, first create a configuration variable: go to Settings → Configuration Variables, create FULLSTORY_API_KEY, mark it as Secret, paste in your API key value. Then return to the resource and use {{ retoolContext.configVars.FULLSTORY_API_KEY }} as the token value.

Click Save Changes. FullStory's REST API is versioned — most endpoints are available at /v1/ or /v2/ paths (check FullStory's API documentation for the current version, as FullStory has been migrating to v2 endpoints). Test the resource by creating a simple query to GET /v1/users and verifying you receive a response.

**Expected result:** The FullStory REST API resource is saved and appears in your Resources list. A test query to /v1/users returns user data, confirming authentication is working.

### 2. Search FullStory users by email or user ID

Create a query to look up FullStory users by their application user ID (the identifier your app uses, which you passed to FullStory's JS snippet as uid). Name the query getFullStoryUser.

Set Method to GET, Path to /v1/users/{{ textInput_userId.value }}. This looks up a user by their application UID. Alternatively, to search by email (which FullStory stores as a custom user variable), use the search endpoint:
- Method: POST
- Path: /v1/users/search
- Body: { "filters": [{ "field": "email", "operator": "==", "value": "{{ textInput_email.value }}" }] }

Note that FullStory's user search uses a filter object structure. FullStory also assigns its own internal user ID (different from your application's UID) — the search results will include both the FullStory uid and the display name.

Drag a Text Input component onto your canvas and name it textInput_email. Create a Search button that triggers the getFullStoryUser query when clicked. Once you have the FullStory user record, you can use the user's ID to query their sessions in the next step.

Display the user information in a JSON viewer or Stat components showing name, email, first seen date, and last seen date from the FullStory user record.

```
// JavaScript transformer — format FullStory user for display
const user = data || {};
return {
  fullstory_uid: user.uid || 'N/A',
  display_name: user.displayName || 'Anonymous',
  email: user.email || 'N/A',
  first_seen: user.firstSeen
    ? new Date(user.firstSeen).toLocaleString()
    : 'Unknown',
  last_seen: user.lastSeen
    ? new Date(user.lastSeen).toLocaleString()
    : 'Unknown',
  session_count: user.sessionCount || 0,
  num_sessions: user.numSessions || 0,
  user_agent: user.userAgent
    ? user.userAgent.split('(')[0].trim()
    : 'Unknown'
};
```

**Expected result:** The user search query returns a FullStory user record matching the entered email or user ID. The transformer formats the user data into a clean summary object for display.

### 3. Fetch user sessions and surface replay links

Create a query to retrieve a user's session list from FullStory. Name it getUserSessions. Set Method to GET, Path to /v1/users/{{ getFullStoryUser.data.uid }}/sessions.

This returns a list of session objects for the user. Each session includes: session ID, session URL (direct link to the replay in FullStory), created timestamp, duration in milliseconds, pages visited, and device/browser information.

Bind this query to a Table component named table_sessions. Configure the session URL column as a URL column type in Retool — this makes each session's replay link clickable, opening the FullStory recording directly in a new browser tab.

Add columns for duration (convert from milliseconds to minutes:seconds format using a transformer), pages visited (count), and created timestamp. Sort by created timestamp descending to show most recent sessions first.

Add a Text component above the table showing the total session count: {{ getUserSessions.data?.length || 0 }} sessions for this user.

Set the query to automatically trigger after getFullStoryUser completes by adding an event handler on getFullStoryUser: On Success → Trigger query → getUserSessions. This creates a seamless two-step lookup: search by email, get user record, automatically load sessions.

```
// JavaScript transformer — format FullStory sessions for table display
const sessions = data || [];
return sessions.map(session => {
  const durationMs = session.durationMs || 0;
  const minutes = Math.floor(durationMs / 60000);
  const seconds = Math.floor((durationMs % 60000) / 1000);

  return {
    session_id: session.sessionId,
    replay_link: session.fsUrl || '',
    started: session.createdTime
      ? new Date(session.createdTime).toLocaleString()
      : 'N/A',
    duration: `${minutes}m ${seconds}s`,
    page_count: session.pageCount || 0,
    browser: session.userAgent
      ? session.userAgent.browser?.name || 'Unknown'
      : 'Unknown',
    device: session.device?.type || 'desktop',
    country: session.geo?.country || 'Unknown'
  };
}).sort((a, b) => new Date(b.started) - new Date(a.started));
```

**Expected result:** The sessions table shows recent FullStory sessions for the looked-up user, with replay links as clickable URLs, duration formatted as minutes:seconds, and sessions sorted by most recent first.

### 4. Pull session events and frustration signals

FullStory's events API lets you pull the event stream from a specific session — every click, navigation, and custom event. More usefully, you can search for specific signal types like rage clicks across all sessions.

Create a query named getSessionEvents. Set Method to GET, Path to /v1/sessions/{{ table_sessions.selectedRow.session_id }}/events. This fetches all events for the session selected in your table.

To specifically search for frustration signals (rage clicks, dead clicks, error clicks) across recent sessions for a user, use the events search endpoint:
- Method: POST
- Path: /v1/events
- Body with filter for event type and user ID

Frustration signals are FullStory's pre-defined events: RageClick (clicking same element 3+ times rapidly), DeadClick (click with no response), ErrorClick (click that triggered a JavaScript error). Surfacing these in a support panel immediately tells agents where the user was frustrated.

For complex support dashboards that combine FullStory frustration signals, Zendesk ticket data, and internal account status — RapidDev's team can help architect the multi-source query design and transformer logic.

Display events in a Timeline-style list using a Retool List component, with icons for different event types (rage click = 🔴, navigation = ➡, custom event = 🟢). This gives a visual timeline of what the user did in the session.

```
// JavaScript transformer — format events into a readable timeline
const events = (data?.events || []);
const eventTypeLabels = {
  'navigate': 'Page Navigation',
  'click': 'Click',
  'input': 'Input',
  'custom': 'Custom Event',
  'exception': 'JavaScript Error',
  'consolemessage': 'Console Message'
};

return events
  .filter(e => e.eventType !== 'mousemove')  // filter out noise
  .map(event => ({
    timestamp: event.timestamp
      ? new Date(event.timestamp).toLocaleTimeString()
      : 'N/A',
    event_type: eventTypeLabels[event.eventType] || event.eventType,
    details: event.targetText
      || event.targetSelector
      || event.url
      || event.message
      || '',
    is_frustration: event.eventType === 'click' && event.frustrationType
      ? event.frustrationType
      : null
  }));
```

**Expected result:** Selecting a session in the sessions table triggers the events query and shows a filtered timeline of events including any frustration signals detected by FullStory for that session.

### 5. Assemble the complete support panel

Bring all the queries together into a complete support panel layout. The finished app gives support agents a single place to understand a user's FullStory history without switching to the FullStory product UI.

Top bar: Email/user ID search input + Search button. Add a Container for the user profile section showing full name, first seen, last seen, and total session count from the getFullStoryUser transformer output.

Middle section: The sessions table showing recent sessions with replay links. Configure a row-click event handler on the sessions table that triggers getSessionEvents. Add a date range filter above the table to limit sessions shown.

Bottom section (split layout): Left — Events timeline for the selected session showing the event type, timestamp, and any frustration signals highlighted in red. Right — An existing ticket or note panel connected to your support system (Zendesk, Freshdesk, or a PostgreSQL notes table).

Add a prominent banner at the top of the events panel when frustration signals are present: {{ getSessionEvents.data.filter(e => e.is_frustration).length > 0 ? 'Frustration signals detected in this session' : '' }}. This immediately draws agent attention to problematic sessions.

Test the complete flow: search for a real user, verify sessions load, click a session, verify events load, check that replay links open FullStory correctly.

```
// JavaScript query — get frustration signal summary for a session
const events = getSessionEvents.data || [];
const frustrationEvents = events.filter(e => e.is_frustration);

return {
  has_frustration: frustrationEvents.length > 0,
  frustration_count: frustrationEvents.length,
  frustration_types: [...new Set(frustrationEvents.map(e => e.is_frustration))],
  rage_clicks: frustrationEvents.filter(e =>
    e.is_frustration === 'RageClick'
  ).length,
  dead_clicks: frustrationEvents.filter(e =>
    e.is_frustration === 'DeadClick'
  ).length,
  error_clicks: frustrationEvents.filter(e =>
    e.is_frustration === 'ErrorClick'
  ).length,
  summary: frustrationEvents.length > 0
    ? `${frustrationEvents.length} frustration signal(s) detected`
    : 'No frustration signals'
};
```

**Expected result:** The complete support panel allows agents to search by email, see session history, select a session to review its event timeline, and identify frustration signals — all without leaving Retool. Replay links in the sessions table open FullStory recordings in a new tab.

## Best practices

- Store the FullStory API key as a Secret configuration variable — FullStory data includes sensitive user behavior information that should be protected.
- Show replay links as URL-type columns in Retool Tables rather than plain text — this makes session investigation one click away for support agents.
- Combine FullStory session data with internal user records in the same Retool app to eliminate context-switching during support investigations.
- Filter events by type before displaying them — mousemove, scroll, and resize events are noise for support investigations; focus on clicks, navigations, custom events, and JavaScript errors.
- Surface FullStory frustration signals (rage clicks, dead clicks, error clicks) prominently in your support panel — these signals instantly indicate where users experienced friction.
- Add session duration and page count columns to the sessions table — very short sessions (under 30 seconds) may indicate users who found a critical error and left immediately.
- Use Retool Workflows to periodically export high-frustration sessions to a dedicated table so your product team can review them in batch rather than only surfacing them reactively during support investigations.
- Implement access controls in Retool to limit FullStory data access to support and product teams — session recordings contain sensitive behavioral data that not all employees should access.

## Use cases

### Build a support ticket enrichment panel

Create a Retool app where support agents enter a user's email to see their recent FullStory sessions alongside their support ticket history. Each session shows its timestamp, duration, pages visited, and a direct replay link. Agents click the replay link to watch what the user did before filing the ticket.

Prompt example:

```
Build a support panel with an email lookup field that runs two queries in parallel: getFullStorySessions for recent user sessions from FullStory's API, and getTickets for open support tickets from Zendesk. Display sessions in a table with replay URLs as clickable links, and tickets in a separate table, both filtered to the same user.
```

### Frustration signal monitoring dashboard

Build a real-time dashboard that surfaces users with high frustration signals — rage clicks, dead clicks, and error clicks — detected by FullStory in the last 24 hours. Link each user to their account in your database to prioritize outreach to churning customers or users stuck in key conversion funnels.

Prompt example:

```
Create a frustration signals dashboard that searches FullStory events for rage click and dead click events in the last 24 hours, joins the user IDs with your customer database to get account tier and ARR, and sorts users by frustration score so customer success can proactively reach out to high-value accounts experiencing friction.
```

### Feature adoption and error tracking panel

Build a Retool dashboard that queries FullStory for specific custom events (like feature usage events you've instrumented with FullStory's JS API) to track feature adoption by user segment. Cross-reference with your user database to understand which customer segments are using which features.

Prompt example:

```
Build a feature adoption panel that queries FullStory events by custom event name for the last 30 days, groups results by user ID, joins with user subscription tier from your database, and shows a bar chart of adoption rate by tier so product managers can see whether premium features are being used by the right segments.
```

## Troubleshooting

### API returns 401 Unauthorized on all requests

Cause: The API key is invalid, expired, or was generated for a different FullStory organization. FullStory API keys are organization-specific and can be rotated in account settings.

Solution: Go to FullStory Admin → Account Settings → Integrations → FullStory API and verify your API key. If the key was regenerated, update the FULLSTORY_API_KEY configuration variable in Retool. Make sure you're using a server-side API key (not the FullStory org ID used in the JavaScript snippet, which is different).

### User search returns empty results even for a known user

Cause: The search is using an identifier (email or user ID) that doesn't match how your application sends user data to FullStory. FullStory only indexes user properties that your application explicitly passes via FS.setUserVars() or the FullStory identify() call.

Solution: Check your FullStory session data directly in the FullStory UI first — search for the user in FullStory's search bar and see what identifier is shown. Match the search field in your Retool query to how FullStory has indexed the user. Common issues include using email when the app only passes uid, or using a numeric ID when the app passes a string.

### Sessions table returns data but replay_link field is empty or null

Cause: FullStory session URLs (fsUrl field) may be absent from the API response for very recent sessions that haven't been fully processed, or for sessions that are still in progress.

Solution: Add a fallback in your transformer that constructs the FullStory URL manually using the session ID and your FullStory org ID: https://app.fullstory.com/ui/YOUR_ORG_ID/session/session_id. Check FullStory's API documentation for the current field name — it may be fsUrl, sessionUrl, or replayUrl depending on the API version.

```
// Fallback URL construction in transformer
const FULLSTORY_ORG = 'YOUR_ORG_ID'; // set in config vars
return sessions.map(session => ({
  ...session,
  replay_link: session.fsUrl
    || `https://app.fullstory.com/ui/${FULLSTORY_ORG}/session/${session.sessionId}`
}));
```

### Event query times out for long sessions with high event volumes

Cause: FullStory sessions with many events (active users, SPAs with lots of interactions) can return thousands of events, causing the API response to be large and slow. Retool's default query timeout may not be sufficient.

Solution: Increase the query timeout in the Advanced settings of your getSessionEvents query to 60 seconds. Add a limit parameter to the events endpoint to fetch only the first 500 events. Better yet, filter by event type to only return navigation and click events (ignoring mousemove, scroll, and other high-frequency events).

## Frequently asked questions

### Can I watch FullStory session recordings inside Retool?

You cannot play FullStory recordings directly within Retool — FullStory's player requires authentication to the FullStory application. What Retool does is show the session metadata (timestamp, duration, pages, frustration signals) and provide direct replay links (fsUrl) that open the session in FullStory in a new browser tab. Your support agents need FullStory viewer licenses to watch the recordings.

### Does FullStory have a native connector in Retool?

No, FullStory does not have a native Retool connector. You connect it using a REST API Resource with Bearer token authentication. The most useful FullStory API endpoints for Retool are the user lookup endpoint, the sessions list endpoint, and the events endpoint — these cover the main support panel use cases without needing the full FullStory data export API.

### How do I match FullStory user IDs with my internal user IDs?

FullStory lets you set a custom uid when identifying users via your JS snippet: FS.identify('your-user-id', { displayName: 'Name', email: 'email' }). If you've implemented this correctly, you can search FullStory by your internal user ID using the /v1/users/{uid} endpoint. If your app only identifies users by email, use the search endpoint with an email filter. The key is that FullStory's user records contain whatever custom properties your app sent during identify().

### What plan do I need for FullStory API access?

FullStory API access is available on Business plans and above. The free trial and some starter plans do not include API access. Check your FullStory Admin → Account Settings section — if you don't see an Integrations or API Keys section, you may need to upgrade your plan. Contact FullStory support if you need API access for evaluation purposes.

### How far back can I query FullStory session data?

FullStory's data retention period depends on your plan — typically 1, 3, or 12 months for Business plans, with custom retention for Enterprise. Sessions older than your retention period are not available via the API. For long-term session data storage, consider using Retool Workflows to periodically export important session data to your own database before it expires in FullStory.

---

Source: https://www.rapidevelopers.com/retool-integrations/fullstory
© RapidDev — https://www.rapidevelopers.com/retool-integrations/fullstory
