Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

FullStory

FullStory connects to Bubble in two paths: inject the JavaScript snippet in Bubble's HTML header to capture all sessions (org ID is public, not a secret), then call FS.identify() after user login to link recordings to specific Bubble users. For read-back, the FullStory REST API lets you query a user's session list and replay URLs from a Bubble admin panel — but requires the FullStory Business plan and an API key marked Private in the API Connector.

What you'll learn

  • How to add FullStory's JavaScript snippet to Bubble's HTML header for automatic session capture
  • How to call FS.identify() from a Bubble workflow after user login to link sessions to user records
  • Why the FullStory org ID is public but the REST API key must be Private
  • How to add the FullStory REST API group in Bubble's API Connector with a Private Bearer token
  • How to build a Bubble admin page that lets support staff look up a user's FullStory sessions and replay links
  • How to configure FullStory element masking to avoid capturing sensitive Bubble form fields
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read2–3 hoursAnalyticsLast updated July 2026RapidDev Engineering Team
TL;DR

FullStory connects to Bubble in two paths: inject the JavaScript snippet in Bubble's HTML header to capture all sessions (org ID is public, not a secret), then call FS.identify() after user login to link recordings to specific Bubble users. For read-back, the FullStory REST API lets you query a user's session list and replay URLs from a Bubble admin panel — but requires the FullStory Business plan and an API key marked Private in the API Connector.

Quick facts about this guide
FactValue
ToolFullStory
CategoryAnalytics
MethodBubble API Connector
DifficultyIntermediate
Time required2–3 hours
Last updatedJuly 2026

Two paths: capture (public org ID snippet) and read-back (private REST API key)

FullStory in Bubble has a clear split that confuses many builders: the JavaScript snippet uses an org ID that is visible in every visitor's browser source, which is correct and intentional — this is not a security flaw. The snippet is a write-only data collector. The private credential in the FullStory integration is the account-level API key used for the REST API, which can read all user and session data across your entire FullStory account — a very different level of access.

The primary Bubble use case for the REST API is a support tool: a Bubble admin page where your support or success team types a user's email, looks up their Bubble user record, retrieves their recent FullStory session list via the API, and clicks a replay link — all without needing a FullStory login. Since Bubble's API Connector runs server-side, the REST API key stays on Bubble's servers and never reaches the browser. CORS is not an issue. This architecture is exactly right for the security model FullStory requires.

Integration method

Bubble API Connector

Uses FullStory's JavaScript snippet for client-side session capture with FS.identify() for user linking, plus the FullStory REST API via API Connector for fetching session lists in a Bubble admin tool.

Prerequisites

  • A FullStory account — snippet capture works on all plans including Developer (free); REST API requires a Business plan or higher
  • Your FullStory org ID (also called org slug) — visible in your FullStory workspace under Settings → General → Org ID
  • A FullStory API key — generated in Settings → API Keys (Business plan required; API key section may not appear on Developer plan)
  • The API Connector plugin installed in your Bubble app (free, by Bubble)
  • The Toolbox plugin installed in your Bubble app (free, by Bubble) for the 'Run JavaScript' action

Step-by-step guide

1

Add the FullStory snippet to Bubble's HTML header

FullStory provides an asynchronous JavaScript snippet that loads the recording library and begins capturing all user interactions on your Bubble app automatically. In your Bubble editor, go to Settings (gear icon in the left sidebar) → SEO / metatags → Script / meta tags in header. In the text area, paste the FullStory snippet. You can find the snippet in your FullStory workspace under Settings → General → FullStory Snippet, or in the onboarding wizard. The snippet contains your org ID — a short alphanumeric identifier like 'ABCDE' — in the initialization call. This org ID is deliberately public: anyone who inspects your page source can see it, just as they can see a GA4 Measurement ID. It is not an API key and has no read access to your FullStory data. After pasting the snippet, save Settings. Publish your Bubble app to a live URL (snippet does not run in Bubble editor preview). Visit the live app, click around for a few seconds, then go to your FullStory workspace and check Sessions — you should see a new session recording appear within 30-60 seconds.

fullstory_snippet.html
1<script>
2 window['_fs_debug'] = false;
3 window['_fs_host'] = 'fullstory.com';
4 window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
5 window['_fs_org'] = 'YOUR_ORG_ID';
6 window['_fs_namespace'] = 'FS';
7 !function(m,n,e,t,l,o,g,y){
8 if (e in m) {if(m.console && m.console.log) { m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'); } return;}
9 g=m[e]=function(a,b,s){g.q?g.q.push([a,b,s]):g._api(a,b,s);};
10 g.q=[];
11 o=n.createElement(t);o.async=1;o.crossOrigin='anonymous';o.src='https://'+_fs_script;
12 y=n.getElementsByTagName(t)[0];y.parentNode.insertBefore(o,y);
13 g.identify=function(i,v,s){g(l,{uid:i},s);if(v)g(l,v,s)};
14 g.setUserVars=function(v,s){g(l,v,s)};
15 g.event=function(i,v,s){g('event',{n:i,p:v},s)};
16 g.anonymize=function(){g.identify(!!0)};
17 g.shutdown=function(){g("rec",!1)};
18 g.restart=function(){g("rec",!0)};
19 g.log = function(a,b){g("log",[a,b])};
20 g.consent=function(a){g("consent",!a===!1)};
21 g.identifyAccount=function(i,v){o='account';v=v||{};v.acctId=i;g(l,v)};
22 g.clearUserCookie=function(){};
23 g.setVars=function(n, p){g('setVars',[n,p]);};
24 g._w={};
25 y='XMLHttpRequest';
26 g._w[y]=m[y];
27 y='fetch';
28 g._w[y]=m[y];
29 if(m[y])m[y]=function(){return g._w[y].apply(this,arguments)};
30 g._v="1.3.0";
31 }(window,document,window['_fs_namespace'],'script','user');
32</script>

Pro tip: Replace 'YOUR_ORG_ID' in the snippet with your actual FullStory org ID. The org ID appears in your FullStory Settings → General page and typically looks like a 5-7 character uppercase alphanumeric string.

Expected result: After publishing and visiting the live Bubble app, a new session appears in FullStory's Sessions view within 60 seconds. The session shows as 'Anonymous' until FS.identify() is called in the next step.

2

Call FS.identify() after user login to link sessions to Bubble users

Without identify(), all FullStory sessions appear as anonymous visitors — useful for heatmap-style analysis but not for support or success use cases where you need to find a specific user's recordings. After a user logs in, call FS.identify() with their Bubble user ID and key traits. In your Bubble editor, find the workflow that runs after successful login — typically the workflow triggered by the 'Log in' button's click action, after the 'Log the user in' step. Add a new step: Action → General → Run JavaScript (Toolbox plugin required). In the JavaScript field, write the FS.identify() call using Bubble's dynamic data syntax to insert the current user's information. The first argument to FS.identify() is the user ID — use the Bubble user's unique ID or your own user identifier field. The second argument is an object of display traits — name and email are the most useful for support teams. These traits appear in FullStory's user search and in the session detail view. The uid you pass here must exactly match what you use later in the REST API lookup — store it consistently.

fullstory_identify.js
1FS.identify('[Current User\'s unique id]', {
2 displayName: '[Current User\'s Full Name]',
3 email: '[Current User\'s email]',
4 plan: '[Current User\'s plan field]',
5 accountId: '[Current User\'s company field]'
6});

Pro tip: In the Bubble 'Run JavaScript' editor, use the 'Insert dynamic data' button rather than typing the bracket placeholders manually. Click 'Insert dynamic data' → 'Current User' → the field you want. Bubble will correctly format the dynamic reference.

Expected result: After a user logs in and the Run JavaScript step executes, future sessions in FullStory appear under the user's name and email in the Sessions list. Clicking a session shows the full replay linked to that specific user's identity.

3

Create the FullStory API group in Bubble's API Connector

The FullStory REST API lets you retrieve a list of sessions for a specific user and get replay URLs programmatically — enabling the support tool use case where staff look up sessions without needing a FullStory account. In your Bubble editor, open Plugins → API Connector plugin. Click Add another API. Name it 'FullStory API'. Set the base URL to 'https://api.fullstory.com'. Under Shared headers for this API, add one header: key is 'Authorization', value is 'Basic YOUR_API_KEY_BASE64'. However, FullStory's REST API uses Bearer token authentication, not Basic auth — add the header as: key 'Authorization', value 'Bearer YOUR_API_KEY'. Mark this header Private by clicking the checkbox next to it. The API key is an account-level credential with read access to all user data and session recordings in your FullStory account — it must never appear in client-side code or a non-Private header. The REST API requires a FullStory Business plan. If the API Keys section does not appear in your FullStory Settings, your current plan does not include REST API access.

fullstory_api_group.json
1{
2 "api_group": "FullStory API",
3 "base_url": "https://api.fullstory.com",
4 "shared_headers": {
5 "Authorization": "Bearer <private: your_fullstory_api_key>"
6 }
7}

Pro tip: Generate a FullStory API key in your workspace under Settings → API Keys → Create API Key. Copy the key immediately — it is shown only once. If you lose it, generate a new one and revoke the old key.

Expected result: The 'FullStory API' group appears in the API Connector with a Private Authorization Bearer header. You are ready to add call definitions.

4

Add the Get Sessions call and initialize it

Inside the FullStory API group, click Add another call. Name it 'Get Sessions'. Set Method to GET and URL to '/v1/users/<uid>/sessions' — where '<uid>' is a path parameter that you will supply dynamically. Under Use as, select Data (this call will feed a Repeating Group). In the Parameters section, mark the 'uid' parameter as a path parameter. For the Initialize call step, you need the exact uid value of a real FullStory user — this is the same uid you passed to FS.identify() (your Bubble user's unique ID or identifier). Paste a real uid into the parameter field for initialization. Click Initialize call. FullStory returns a list of session objects, each containing fields including: 'FsUrl' (the direct FullStory replay link), 'CreatedTime' (session start timestamp), 'Duration' (in milliseconds), 'UserAgent', and 'NumEvents'. Bubble maps these fields automatically. After initialization, set the 'Type of content' to List so this call can feed a Repeating Group. In your workflow or page data source, supply the uid dynamically — for example, 'Current User's unique id' or the uid retrieved from a user lookup workflow.

fullstory_get_sessions_call.json
1{
2 "method": "GET",
3 "url": "https://api.fullstory.com/v1/users/<uid>/sessions",
4 "headers": {
5 "Authorization": "Bearer <private: api_key>"
6 },
7 "parameters": {
8 "uid": "<dynamic: bubble user unique id>"
9 }
10}

Pro tip: If the Initialize call returns 'There was an issue setting up your call', the most likely cause is an invalid uid or an expired/incorrect API key. Verify the uid exists in FullStory by searching for it in the FullStory Users section before using it for initialization.

Expected result: The Get Sessions call initializes successfully. Bubble detects session fields including FsUrl, CreatedTime, and Duration. These fields are available to bind in a Repeating Group on the next step.

5

Build the Bubble support admin page

Now build the Bubble page where support staff look up a user's FullStory sessions. In your Bubble editor, create a new page (or use an existing admin page). Add a text input element labeled 'Search by email'. Add a Repeating Group element below it to show search results (Bubble users matching the email). In the Repeating Group's data source, use a 'Search for Users where email contains Input's value'. Add a 'Get Sessions' button in each row of the first Repeating Group. When clicked, the button workflow calls the FullStory API Get Sessions action with the current row's unique ID as the uid parameter, stores the result in a Custom State (a list of Session objects), and shows a second Repeating Group of sessions. In the sessions Repeating Group, bind each row to the Custom State list. Show the session creation date (CreatedTime), duration in seconds (Duration / 1000), and add a Link element or 'Go to external link' workflow action that opens the FsUrl in a new browser tab. Apply Bubble Privacy Rules to ensure this admin page is only accessible to users with an 'Admin' or 'Support' role. Staff who access this page can view FullStory sessions for any user in your app, so the privacy restriction is important.

Pro tip: RapidDev's team has built hundreds of Bubble apps including support tools that surface FullStory replays inside Bubble admin panels. If you need help wiring the role-based access controls or the session lookup workflow, book a free scoping call at rapidevelopers.com/contact.

Expected result: The support admin page shows a user search input. Entering an email displays matching Bubble users. Clicking 'Get Sessions' for a user loads their FullStory session list with replay links. Clicking a replay link opens the FullStory player in a new tab.

6

Configure FullStory element masking and privacy settings

FullStory records everything a user types and sees in your Bubble app by default. For most SaaS apps, this is too broad — password fields, payment card inputs, and sensitive personal data should never appear in session recordings. FullStory's solution is element exclusion classes: adding the CSS class 'fs-exclude' to a Bubble element tells FullStory to mask that element in recordings (input values are replaced with asterisks, and the element itself may be hidden in the replay). In your Bubble editor, select the input element you want to mask. In the right-side properties panel, find the 'Appearance' section and look for 'Additional CSS classes'. Type 'fs-exclude' in this field. Repeat for password inputs, SSN fields, credit card inputs, and any other sensitive data fields. Alternatively, 'fs-mask' masks just the input value while still showing the element outline in the replay — useful for seeing that the user interacted with a field without seeing what they typed. Also review FullStory's privacy settings in the dashboard: Settings → Privacy → Data Collection to configure global masking rules by element type.

fullstory_privacy_classes.css
1/* Add to individual sensitive Bubble elements via 'Additional CSS classes': */
2
3/* Completely exclude from recording (element hidden in replay): */
4fs-exclude
5
6/* Mask the value only (element visible, content asterisked): */
7fs-mask
8
9/* Stop recording entirely on an element and its children: */
10fs-stop

Pro tip: Test your privacy masking in a staging environment by triggering a session, then reviewing the recording in FullStory to confirm sensitive fields are properly masked. Do not rely on configuration alone — verify the masking is working before going to production.

Expected result: Sensitive input fields in your Bubble app appear masked in FullStory session recordings. Password and payment fields show asterisks in replays, protecting user privacy while still allowing support teams to see the overall session flow.

Common use cases

Support tool with user session replay lookup

Build a Bubble internal admin page with an email search input. Support staff type a user's email, Bubble looks up the matching user record, retrieves the FullStory uid stored on the user, calls the FullStory REST API for that user's recent sessions, and displays a list of session replay links. Staff click a link and open the FullStory player in a new tab — resolving 'I don't know what the user clicked' support tickets in seconds without needing to give every support agent a FullStory account.

Bubble Prompt

Copy this prompt to try it in Bubble

Onboarding friction detection

Every new user's session is captured by FullStory automatically via the snippet. Tag new users at signup with a Bubble 'Run JavaScript' identify call that includes a 'user_type: new' trait. In FullStory, create a segment of users who never completed the onboarding flow (based on events). Watch replays of those specific sessions to identify where they got stuck — a Bubble form field that was confusing, a button that was hard to find, or a modal that blocked their flow.

Bubble Prompt

Copy this prompt to try it in Bubble

Customer success team health check dashboard

For B2B Bubble apps with named accounts, use FS.identify() to tag every user with their company name and account tier as traits. Build a Bubble dashboard that lists accounts, shows the last session date per account (retrieved via the FullStory REST API), and flags accounts with no sessions in the past 30 days as 'at-risk'. Customer success managers see a health indicator for each account without logging into FullStory.

Bubble Prompt

Copy this prompt to try it in Bubble

Troubleshooting

FullStory sessions show as 'Anonymous' even after FS.identify() is called in a Bubble workflow

Cause: Bubble's 'Run JavaScript' action may run before the FullStory snippet has fully loaded on the page, causing the FS object to be undefined when the identify call executes. This is especially common if the identify workflow runs on page load immediately.

Solution: Add a conditional check in the JavaScript: `if (window.FS && FS.identify) { FS.identify(...) }`. If you need to guarantee identify fires after the snippet loads, use a small delay or trigger the workflow from a later workflow step (e.g., after a successful login API call completes) rather than on page load. Alternatively, use the FullStory REST API's /v1/users endpoint to set user vars server-side.

typescript
1if (window.FS && typeof FS.identify === 'function') {
2 FS.identify('[Current User\'s unique id]', {
3 displayName: '[Current User\'s Full Name]',
4 email: '[Current User\'s email]'
5 });
6}

FullStory REST API calls return 403 Forbidden

Cause: The FullStory account is on a Developer (free) or lower plan that does not include REST API access. The /v1/users and /v1/users/{uid}/sessions endpoints require a Business plan or higher.

Solution: Check your FullStory plan in Settings → Billing. If the API Keys section is absent from your Settings menu, your plan does not include API access. Upgrade to FullStory Business plan to enable REST API access. The JavaScript snippet and FS.identify() work on all plans including free.

API Connector shows 'There was an issue setting up your call' when initializing the Get Sessions call

Cause: The uid parameter used during initialization does not match any user in FullStory, the API key is missing or incorrect in the Authorization header, or the FullStory API endpoint version has changed.

Solution: Verify the uid by going to FullStory → Users → search for a user you have identified. Copy the exact uid from their user profile. Paste it into the API Connector initialization parameter field. Confirm the Authorization header contains 'Bearer ' followed by your API key (with a space after 'Bearer'). If the API returns a different error code, check FullStory's API documentation for the current endpoint URL.

FullStory records sessions in Bubble editor preview but no sessions appear for the published app

Cause: FullStory's snippet is loading from Bubble's Settings → SEO / metatags, which applies only to the published app. In the Bubble editor preview, the snippet may load from the test environment, which FullStory may track separately or not at all.

Solution: Publish your Bubble app and test from the live production URL (not /version-test). Check FullStory's Sessions and confirm the sessions are associated with your production domain. If you see sessions from both test and production environments in FullStory, filter by domain in the FullStory Session list to isolate production traffic.

The UID passed to FS.identify() in Bubble contains special characters that break the REST API session lookup

Cause: Bubble's unique ID format (e.g., '1644123456789x123456789012345678') contains only alphanumeric characters and is safe. However, if you use a custom identifier field (like an email or username with special characters), URL encoding in the API Connector path parameter may cause a mismatch.

Solution: Use Bubble's built-in unique ID (the 'unique id' field available on all data types) as the FullStory uid rather than email or display name. Unique IDs contain only alphanumeric characters and are safe in URL paths. If you must use another identifier, ensure consistent URL encoding in both the FS.identify() call and the API Connector path parameter.

Best practices

  • Always use Bubble's built-in unique ID (not email or display name) as the FullStory uid passed to FS.identify(). Unique IDs are stable, URL-safe, and do not change when users update their profile information.
  • Apply 'fs-exclude' or 'fs-mask' CSS classes to all sensitive Bubble input fields — password inputs, credit card fields, SSN, date of birth, and any other personally identifiable data. Review the masking in a test session before going to production.
  • Store the FullStory REST API key as Private in the API Connector's shared header. The API key provides read access to all user data and session recordings across your entire FullStory account — treat it with the same sensitivity as a database password.
  • Restrict the Bubble admin page that displays FullStory session links using Privacy Rules and role-based conditions. Only support staff and admins should be able to look up and view another user's session recordings.
  • Use the FullStory REST API sparingly in workflows to manage Workload Unit (WU) consumption. Fetching a session list on every page load for every user is wasteful — trigger the API call only when a support agent actively searches for a specific user.
  • If you are on the FullStory Developer (free) plan, the JavaScript snippet and FS.identify() provide most of the value for session capture and user identification. Plan the REST API read-back features only once you have confirmed the Business plan is within budget.
  • Review FullStory's data retention settings for your plan. Sessions are typically retained for 1-3 months depending on the plan. If support staff need to access older sessions, plan accordingly or export session data before it expires.
  • Apply Bubble Privacy Rules to any Bubble data type that stores FullStory session URLs or session metadata. Session replay URLs grant direct access to a recording — treat them as sensitive data and restrict their visibility to authorized roles.

Alternatives

Frequently asked questions

Is the FullStory org ID in the snippet a secret I need to protect?

No. The FullStory org ID is a public identifier intentionally included in client-side JavaScript. Anyone who views your page source can see it, just as they can see a Google Analytics Measurement ID. It is a write-only capture credential — someone who obtains your org ID can only send data to your FullStory source, not read your recordings, user data, or account settings. The secret credential that requires protection is the FullStory REST API key used for read-back.

Do I need the FullStory Business plan for the integration?

For basic session capture and user identification (snippet + FS.identify()), the Developer (free) plan is sufficient. For the REST API calls that retrieve session lists and replay URLs — the read-back part of the integration — you need a FullStory Business plan or higher. If API Keys do not appear in your FullStory Settings menu, your plan does not include REST API access.

Can FullStory record what users type in Bubble input fields?

Yes, by default. FullStory captures all text inputs including what users type in Bubble inputs, selects in dropdowns, and other form interactions. This is intentional for support use cases but may create privacy and compliance issues for sensitive fields. Use the 'fs-exclude' or 'fs-mask' CSS classes on sensitive Bubble input elements to prevent recording their content. Review FullStory's Privacy settings dashboard for account-wide masking rules.

Does Bubble consume Workload Units (WU) for the FullStory snippet?

No — the JavaScript snippet fires from the user's browser, not from Bubble's server. It does not consume any Bubble Workload Units. WU are only consumed by Bubble server-side operations (API Connector calls, backend workflows, database operations). The FS.identify() call in a 'Run JavaScript' workflow action similarly runs client-side and does not consume WU. Only the FullStory REST API calls made via the API Connector consume WU.

Can I use FullStory to track Bubble's internal editor pages?

FullStory only captures sessions on your published Bubble app's live URL — not in the Bubble editor preview. The snippet in Settings → SEO / metatags applies to the published app. For tracking editor behavior or preview sessions, you would need a different approach. For most use cases, tracking only the live production app is the right behavior.

What happens if a user's FullStory session is captured before they log in (anonymous) and then they log in?

FullStory automatically merges anonymous session data with the user identity when FS.identify() is called during the same browser session. All previous interactions in that session are associated with the identified user retroactively. Across sessions, FullStory uses its identity resolution to link pre-login anonymous events to the user after identification.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.