Skip to main content

The Embeddables Platform

Compliance & Security

Yes, we are HIPAA compliant. However, customers need to follow our HIPAA compliance checklists and requirements to maintain compliance.
No, we are not SOC2 compliant at this time.
No, we do not sign BAAs.

Data Processing & Privacy

Our platform is used to build and embed frontend components. These components are then embedded or hosted on your website.The amount of data we process depends on your preferences. If you want to use our platform’s analytics features, then our platform collects data from your end-users such as IP addresses, browser information, and page views.If you don’t want to use our platform’s analytics features, then we don’t need to collect, process, or store any personal end-user data.You can choose instead to collect and store data through your own backend. You can send directly from the user’s browser to your designated backend without it passing through our infrastructure.
Customers on our Pro and Enterprise plans can request us to review and sign a DPA.For customers on lower plans, if you require a DPA with any vendors who process personal data, then we recommend that you send data directly from the user’s browser to your backend, without passing through our infrastructure (which would disable most of Embeddables’ built-in analytics features).
We do not currently have a DPIA.

Infrastructure & Hosting

Our platform is hosted on the following providers:
  • Cloudflare
  • Vercel
  • Heroku
  • Supabase
  • Firebase
  • Clickhouse
Our codebase itself is hosted on GitHub.
No, Embeddables are not embedded using iframes. They are embedded directly into your page as native HTML/CSS/JavaScript components.This approach provides several benefits:
  • Better performance and faster load times
  • Seamless integration with your page’s styling
  • No cross-origin restrictions
  • Better SEO as content is part of your page
  • Easier data passing between your site and the Embeddable
  • Better support for Stripe payments, since Stripe uses its own iframes (avoiding nested iframes)

Building with Embeddables

Troubleshooting

If your Builder is not loading or appears to be stuck in an infinite loop, check if any Computed Field keys share the same name as other keys in your User Data (such as option button keys or other input field keys).Problem: Computed Fields with the same name as other keys can cause infinite loops that prevent the Builder from loading.Solution: Rename the Computed Field to have a unique key name. For example, if you have an option buttons field called health_conditions_options, rename your Computed Field to something like health_conditions_options_cf (adding a suffix like _cf for “Computed Field”).
Computed Field keys must be unique and cannot share the same name as any other key in your User Data JSON object.
If you can’t fix your changes because the Builder doesn’t load, the problem is likely on the latest version. Switch to the previous version (if possible) and save from there. You’ll need to redo your latest changes without causing the bug.

Logic

If you need to find where a specific User Data key is being created or updated in your Embeddable, you can search through the entire Embeddable JSON.How to search:
  1. Open the Builder for your Embeddable
  2. Press ESC to deselect any components (so nothing is selected)
  3. In the Options sidebar, click the three dots menu (⋮) in the top right corner
  4. Click “Edit JSON” to open the JSON editor modal
  5. Use the search inside the code editor box (Cmd+F or Ctrl+F with the code editor in focus) to search for the key name within the JSON
This will show you all locations where that key appears in your Embeddable configuration, including:
  • Input fields and form components that create the key
  • Actions that update the key
  • Computed Fields that are set with their key as the key you’re looking for, or that reference the key
  • Conditions that use the key
We’re working on shipping a better global search feature that will make this process easier. For now, searching the Entire Embeddable JSON is the most reliable way to find where keys are being used.

Design, Styling, and Layouts

To place components side by side (horizontally), first those components need to be inside a container.
  1. Add a container to the page if it does not already exist.
  2. For each component that you want to align horizontally, move it into the container.
  3. Select the container, and in the Designer sidebar, set the display property to flex.
  4. Ensure the flex direction is set to row (this is usually the default).
If components are still stacking vertically, check that the container does not have flex-direction: column set.
When you want to center a button horizontally on your page, place the button inside a container and use flexbox to center it.
  1. Select the container that includes ONLY the button (or create one if it doesn’t exist).
  2. In the Designer sidebar, set the container's width to 100%.
  3. Set the display property of the container to flex.
  4. Ensure the flex direction is set to row (this is usually the default).
To apply different styles for mobile, tablet, and desktop:
  1. Select the component you want to style.
  2. In the Designer sidebar, look for the “On” dropdown.
  3. Choose the specific screen size you want to style for:
    • Mobile: up to 520px width
    • Tablet: 521px to 720px width
    • Desktop: 721px width and above
  4. Apply your styles while that screen size is selected - this will set the styles for only that screen size and smaller screen sizes.
The device screen type options in the Builder allow you to preview how your content will appear on different screen sizes:
  • Mobile: Shows layout for devices with width up to 520px.
  • Tablet: Shows layout for devices with width between 521px and 720px.
  • Desktop: Shows layout for devices with width of 721px and above.
These are preview modes that help you see how your design will look on different devices. To actually edit styles for specific screen sizes, use the “On” dropdown in the Designer sidebar. You can also use the “On” dropdown to preview how your design will look on different screen sizes.
In our Builder, styles cascade downward from larger screens to smaller screens, similar to how CSS works. This means:
  • Desktop styles (721px+) apply to desktop, tablet, and mobile
  • Tablet styles (521px-720px) apply to tablet and mobile
  • Mobile styles (up to 520px) apply only to mobile
This design choice was made based on feedback because most Embeddables users design for desktop first, then adapt for smaller screens.To fix unwanted style inheritance:
  1. Select the component that has unwanted styles on mobile
  2. Switch to Mobile view using the “On” dropdown in the Designer sidebar
  3. Override the problematic styles by setting different values for mobile
Example: If you set a width of 300px on desktop but want full width on mobile:
  • Desktop: width = 300px
  • Mobile: width = 100%
Button components contain several elements you can style individually:
  • Whole thing: Apply styles to the entire button (background, border, etc.).
  • Text Wrapper: Style the container that holds the button’s text.
  • Text: Style the text itself (font, color, size, etc.).
  • Description: Style any description text (if present).
  • Icon: Style the icon (if present).
  • Image: Style any image within the button (if present).
The available elements depend on what content your button contains. For a simple text button, you’ll primarily use “Whole thing”, “Text Wrapper”, and “Text”.
If your Embeddable appears different when embedded on your website compared to the builder preview, this is typically caused by CSS conflicts between your website’s global styles and the Embeddable’s styles.Common causes:
  • Global CSS styles on your page are overriding the Embeddable’s styles
  • Margin or padding applied to elements inside the Embeddable (e.g., body margins preventing edge-to-edge display)
  • Font styles or other inherited CSS properties from your page
  • CSS reset or normalize stylesheets affecting the Embeddable’s layout
How to fix:
  1. Inspect the Embeddable on your website using browser developer tools (right-click → Inspect)
  2. Look for conflicting styles that are being applied from your website’s CSS
  3. Override the conflicting styles by adding more specific CSS rules to your page:
  1. Test the changes to ensure the Embeddable displays correctly
The Embeddable is embedded as native HTML/CSS/JavaScript (not an iframe), which means it inherits styles from your page. This provides better performance and integration but requires careful CSS management.

Form Elements

You can disable a button based on whether inputs on the page are completed or validated directly from the button settings.
  1. Select the button you want to configure.
  2. In the button settings, find the Validation section.
  3. Look for the option “React if page requirements not met”.
  4. Set it to “Disable”.
The button will automatically be disabled if the inputs on the page aren’t completed or validated. Once all required inputs are filled and validated, the button will become enabled.
This works with any input fields that have validation rules set up. The button will check all inputs on the page and disable itself if any requirements aren’t met.
To access multiple form element values in a Computed Field, you can pull the keys of each input component from the first argument of the function.
The Computed Field receives a single object containing all your form element results. Make sure the property names in the destructuring match exactly with your form element names.
  1. Add a regular Input component.
  2. In the Options tab, set the Input Type to Phone.
Optional: To validate the phone number:
  1. Under the Validation section, check Validate value.
  2. Set Formula to Phone Number (US) or Custom formula.
  3. If you choose Phone Number (US), the phone number will be automatically formatted as (xxx) xxx-xxxx.
  4. If you choose Custom formula, you can use the something like the following formula to validate the phone number:
This formula will allow numbers, parentheses, spaces, and dashes.
Yes, there are several approaches to restrict phone input to numbers only:The simplest and most reliable approach is to use the built-in phone validation:
  1. Set the Input component’s Input Type to Phone
  2. In the Validation section, check Validate value
  3. Set the Formula to Phone Number (US)
This automatically:
  • Formats the number as (xxx) xxx-xxxx as the user types
  • Validates the format is correct
  • Provides a consistent user experience
  • Handles edge cases and formatting automatically
The built-in validation is the most reliable option and handles all US phone number formats automatically.

Option 2: Custom validation with regex

For more control over the validation rules, you can use a custom formula:
  1. Set the Input component’s Input Type to Phone
  2. In the Validation section, check Validate value
  3. Set the Formula to Custom formula
  4. Write a custom function to validate the phone number, for example:
Custom validation gives you more control but requires more testing and maintenance. The built-in option is recommended for most use cases.

Option 3: Remove disallowed characters immediately on type, using a custom action

Create an action that runs on page load to restrict input to numeric characters only:
Using custom actions to restrict input may interfere with the automatic phone number formatting. The built-in phone validation is simpler and more reliable.
Yes! When you set an Input component’s type to Phone, and choose Phone Number (US) for validation, it automatically formats the number as (xxx) xxx-xxxx as the user types.This provides a better user experience and ensures consistent formatting across all submissions.
The automatic validation won’t prevent users from entering text, but it will prevent them from submitting the form if the phone number is invalid, showing them a validation error message.

Versions & Publishing

Yes. When you edit an old version and save it, those edits become the newest version.However, you’ll receive a warning before saving that alerts you that you’re about to skip/overwrite changes from other versions. This means your new version will include your changes but will not include changes made in the intervening versions.The Builder will show a “From version XXX” message in the Version Control card to indicate which version you’re editing from.
To avoid accidentally overwriting recent changes, always check the Version Control card to see which version you’re currently editing before making changes.
To roll back to a previous version:
  1. Open the Version Control card in the Builder sidebar.
  2. Find the version you want to roll back to in the version history list.
  3. Click on that version to load it in the Builder.
  4. Make a small edit (the Save button won’t be active until you make a change).
  5. Click Save - this creates a new version based on the old one.
When you save, you’ll see a warning that you’re about to skip/overwrite changes from intervening versions. This is expected when rolling back.
Rolling back creates a new version based on the old one, but does not include changes made in versions between the old version and the current version. Those changes will be skipped.
The rolled-back version becomes your newest version. You can always access any previous version (including the ones you rolled back from) in the version history.
To view the audit trail of staging and production deployments:
  1. Click on Version Control in the top bar of the Builder.
  2. Go to the Logs tab.
  3. This shows an audit trail of staging and production deployments.
The Logs tab provides a complete audit trail of staging and production deployments, including timestamps and version numbers.
To see what changed between two versions:
  1. Open Version Control in the Builder Top Bar.
  2. Click the <> icon (compare icon) in Version Control.
  3. Select the two versions you want to compare.
This will show you the differences between the selected versions, helping you understand what edits were made.
This is especially useful when you need to understand what changed between an older version and the current one, or when investigating performance differences between versions.

Data & Analytics

Your users’ data can be found in two places:
  1. Users page
    • Shows individual user sessions.
    • You can click on a user to see their activity and their submission data for each Embeddable.
  2. Embeddable —> Submissions tab
    • Shows the User Data for completed form submissions.
    • Each user will have a separate row for each Embeddable they have interacted with, meaning there could be multiple rows for the same user.
    • All users from all stages of the funnel are included, so the majority of rows will likely correspond to users who did not reach the end of the funnel.
To switch between viewing production data vs viewing all data (including test data):
  1. Go to your funnel dashboard.
  2. Look for the “Data collected in production version” button.
  3. Click it to toggle between:
    • Production data only
    • All data (including both production and test data)
If you cannot see user details or search for users by email address, this is likely due to your data access permissions. This restriction is in place to maintain HIPAA Compliance and protect sensitive user information.Why this happens:
  • Your workspace has HIPAA Compliance enabled, which restricts access to personally identifiable information (PII) and protected health information (PHI).
  • Your account has Anonymized Data Access, which means you can only view anonymized data—personally identifiable information about end-users is hidden.
  • Email addresses are classified as contact information and PII, so they are not visible to users with Anonymized Data Access.
How to get access:To view user details and search by email address, you need Full Data Access permissions. Contact your workspace Admin or Data Privacy Officer to request an access level upgrade.Your Admin can update your permissions by:
  1. Going to SettingsTeam tab
  2. Finding your user in the table
  3. Changing your Data Access Level to Full Data Access
Full Data Access should only be granted to team members who have a clear, documented need to view personally identifiable or health information. This is a HIPAA Compliance requirement.
For more information, see:

CLI

No. Install globally with npm install -g @embeddables/cli. Your project only needs the files created by embeddables init (including .types/ for editor support). You do not add @embeddables/cli as a dependency in package.json for normal use.
Login is stored globally on your machine (not per project). Use embeddables logout to clear it.
You can build and save Embeddables entirely from the CLI. The Builder is still the recommended place to create experiments, upload assets, and for non-technical teammates to review and merge. Many teams use both: CLI for fast iteration and AI-assisted edits, Builder for final review and publishing.
Both must be unique in context. id is the stable internal identifier (e.g. comp_12345). key is used in React and for targeting (e.g. in conditions or user data). Keys must not start with a number; use a prefix like option_ or range_ if the label would otherwise slug to a number.
Yes. Run embeddables pull for each; they live in embeddables/<embeddable-id>/. When you run embeddables dev, embeddables save, or embeddables branch without -i, you’ll be prompted to choose which Embeddable to use. To avoid the prompt, go into that Embeddable’s folder (e.g. cd embeddables/<EMBEDDABLE_ID>) and run the command from there—the CLI will automatically use that Embeddable.
Use embeddables pull —preserve. It keeps the same order of components in the config. Most of the “changes” you see on a first pull are from React reordering components within containers—that doesn’t affect how the Embeddable renders. With —preserve, you may still see smaller changes (e.g. parent_key fixes), but it’s easier to verify what actually changed.
Use embeddables dev --local to use http://localhost:8787. Or use embeddables dev --engine https://your-engine.example.com for a custom URL.
The Workbench is a debugging panel that lets you inspect user data, computed fields, actions, and navigate pages. On localhost previews from embeddables dev, it is shown by default; add ?workbench=false to hide it. On non-localhost preview links, add ?workbench=true to show it. It is served by the dev proxy and does not require a separate deploy.
Yes. The CLI is designed for AI-assisted editing. Running embeddables init injects Cursor rules (.cursor/rules/), Claude project context (.claude/), and a Codex-compatible AGENTS.md file so the assistant understands the file layout, component types, and conventions. You can also use the built-in prompts from the CLI repo in your own rules.
Run embeddables upgrade. You can check the current version with embeddables -v.
You can create new branches with embeddables branches create and switch between them with embeddables branch. Creating experiments is still done in the Builder; use embeddables experiments connect to link an existing experiment to your Embeddable.
Someone (in the Builder or via the CLI) saved a newer version after you last pulled. You can pull the latest with embeddables pull and then re-apply your changes, or force-save when the prompt offers it (use with care to avoid overwriting others’ work).
Global components are shared across pages (e.g. a nav bar or footer). They live in embeddables/<id>/global-components/ with one file per location, e.g. before_page.location.tsx, after_components.location.tsx. The _location value controls where they render relative to the page.
We don’t currently recommend using version control (e.g. Git) in your codebase for the Embeddable files, because it can easily get out of sync with Embeddables’ own version and branch system.Instead, use embeddables diff to compare your local files against the last saved cloud version:
For a raw JSON diff, open embeddable.json and the latest embeddable-<branch>@<version>.json (e.g. embeddable-main@47.json) inside the .generated/ folder. In VS Code or Cursor: Shift+click or Command/Ctrl+Click to select both files, then right-click → Compare Selected.
If you see a huge number of changes after pulling, try using the --preserve flag with the pull command to keep the same order of components in the config.
The Embeddables team is exploring internally various ways of integrating with version control systems like Git and GitHub.If you have any feedback or ideas on how you could envisage this working, please reach out, we’d love to bounce ideas off you!