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:
/* Example: Remove body margin affecting the Embeddable */
.embeddables-container body {
  margin: 0;
}

/* Example: Reset specific styles for the Embeddable */
.embeddables-container * {
  box-sizing: border-box;
}
  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.
// Computed Field: full_name
function result(userData) {
  return `${userData.first_name} ${userData.last_name}`;
}
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:
function validate(value) {
  return /^[\d\s\(\)\-]+$/.test(value);
}
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:
function validate(value) {
  return /^[\d\s\(\)\-]+$/.test(value);
}
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:
function output(_, { setUserData }) {
  const input = document.querySelector(".ComponentKey-phone input");
  if (!input) return;

  input.setAttribute("inputmode", "numeric");

  input.addEventListener("input", (e) => {
    let value = e.target.value;
    let digits = value.replace(/\D/g, '');

    if (digits.length > 10) {
      digits = digits.slice(0, 10);
    }

    // Remove letters but keep formatting characters
    value = value.replace(/[A-Za-z]/g, '');
    e.target.value = value;
  });
}
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: