Typeform

Article author
Memberstack Team

You can use the new Memberstack 2.0 front-end API and the following code to inject Typeform embedded widgets with hidden fields on your page.

Create the Typeform Widget

Place the following code at the end of the body section of whatever page you want the form to appear.

<script>
  // Replace 'qVTlfl9j' with your unique Typeform ID
  const TYPEFORM_ID = 'qVTlfl9j';

  // The config below matches Typeform hidden field IDs to corresponding Memberstack field IDs
  // Add an object for every field you want to pass to Typeform
  const TF_CONFIG_MAP = [
    {
      typeform_field_id: 'first_name', // Typeform field ID
      memberstack_field_id: 'customFields.first-name', // Memberstack field ID
    },
    {
      typeform_field_id: 'phone', // Typeform field ID
      memberstack_field_id: 'customFields.phone', // Memberstack field ID
    },
  ];

  // Function to generate hidden fields for Typeform based on Memberstack data
  function generateHiddenFields({ config, member }) {
    if (!config) return []; // Return empty array if config is not provided

    const fields = config.map((key) => {
      const { memberstack_field_id, typeform_field_id } = key;
      const ms_field_value = memberstack_field_id
        .split('.')
        .reduce((acc, val) => acc[val], member) || ''; // Default to empty string if field is undefined
      return `${typeform_field_id}=${encodeURIComponent(ms_field_value)}`; // URL-encode the field value
    });

    // Add member ID and email to the fields
    fields.push(`memberstack_id=${encodeURIComponent(member.id)}`);
    fields.push(`email=${encodeURIComponent(member.auth.email)}`);
    return fields.join(','); // Join fields into a single string
  }

  // Function to generate the Typeform string with hidden fields
  const GENERATED_TYPEFORM_STRING = (member) => {
    return generateHiddenFields({
      config: TF_CONFIG_MAP,
      member,
    });
  };

  // Function to inject the Typeform widget into the page
  function injectTypeform(member) {
    const tfEl = document.createElement('div'); // Create a new div element
    const anchor = document.getElementById('tf-wrapper'); // Get the anchor element where Typeform will be injected

    tfEl.id = 'tf-form'; // Set the ID of the div element

    // Set Typeform attributes
    tfEl.setAttribute('data-tf-widget', TYPEFORM_ID);
    tfEl.setAttribute('data-tf-inline-on-mobile', true);
    //tfEl.setAttribute('data-tf-hide-headers', true); // Uncomment to hide headers
    tfEl.setAttribute('data-tf-transitive-search-params', true);
    tfEl.setAttribute('data-tf-medium', 'snippet');

    console.log('generated: ', GENERATED_TYPEFORM_STRING(member)); // Log the generated Typeform string
    tfEl.setAttribute('data-tf-hidden', GENERATED_TYPEFORM_STRING(member)); // Set hidden fields
    tfEl.setAttribute('style', 'height:100%'); // Set the height of the div
    tfEl.style.width = '100%'; // Set the width of the div

    anchor.appendChild(tfEl); // Append the Typeform div to the anchor element

    const typeformScript = document.createElement('script'); // Create a new script element
    typeformScript.setAttribute('src', '//embed.typeform.com/next/embed.js'); // Set the source of the script

    document.head.appendChild(typeformScript); // Append the script to the head of the document
  }

  // Get the current Memberstack member and inject the Typeform widget when member data is ready
  window.$memberstackDom.getCurrentMember().then(({ data: member }) => {
    if (member) {
      injectTypeform(member);
    }
  });
</script>

ℹ️ Memberstack's getCurrentMember() method runs after the page loads, so the member data isn’t available right away. This means we can’t statically embed a Typeform widget with hidden member fields because the member data will be undefined at first.

To solve this, we must use JavaScript (above) to dynamically create a form widget when member data is ready and then inject it on the page.

Map Input Fields

You can pass as many key-value sets of Typeform and Memberstack fields that you want inside of the TF_CONFIG_MAP array.

This configuration array will later be passed to a special Memberstack API method that returns a properly formatted string (of dynamic member data) that Typeform expects on the form widget’s data attributes.

The config array is just a set of objects that describe the field IDs for Typeform and Memberstack respectively. (You don't need to copy/paste this code again).

// The config below matches Typeform hidden field IDs to corresponding Memberstack field IDs
// Add an object for every field you want to pass to Typeform
const TF_CONFIG_MAP = [
  {
    typeform_field_id: "first_name", // Typeform field ID
    memberstack_field_id: "customFields.first-name", // Memberstack field ID
  },
  {
    typeform_field_id: "phone", // Typeform field ID
    memberstack_field_id: "customFields.phone", // Memberstack field ID
  }
];

⚠️ Make sure you’re spelling Typeform field IDs and Memberstack custom fields exactly as they appear. For more info on Typeform attributes, see here.

For each object you pass in the array, replace the YOUR_TYPEFORM_FIELD_ID and YOUR_FIELD_ID placeholders with the corresponding field IDs for each service.

{ 
 typeform_field_id: "YOUR_TYPEFORM_FIELD_ID",
 memberstack_field_id: "customFields.YOUR_FIELD_ID" }

The custom field ID can be found on each custom field’s settings popup.

Was this article helpful?

Comments

10 comments

  • Comment author
    Daniel Linger
    • Edited

    Hi, I have added this code to my Webflow html embed & have updated with everything that is necessary such as form id, type form id & member-stack field id, but it doesn't work.

    I have looked into console & It give member error.

    Can anybody please help me out.

    Is there anything that I am doing wrong, can anybody please help me out.

    0
  • Comment author
    Josh Lopez

    Just updated the code and i tested it. It should work now.

    0
  • Comment author
    Simon Childs

    Hi memberstack team!

    I was hoping you could help. This is really handy and I have got it working for Memberstack information.

    However, I would like to parse through Webflow CMS information at the same time. So as well as Typeform recognising the logged-in user details, I can send through the page title and other CMS items. This is easily done on its own, but I am not sure how to achieve it at the same time as sending through the Memberstack info as above. 

    Thanks in advance! 

    1
  • Comment author
    Caasly null

    I'm unable to get this working.  have ticket open with memberstack 

    #8985

    also have request open in slack chat under bugs

    0
  • Comment author
    Mauro Arancibia

    is this code still working? it would be nice if you guys can reply because it doesn't for me.

    0
  • Comment author
    Josh Lopez

    Hey Mauro Arancibia!

    I just updated the code slightly. I also added more comments to help explain things better. If this new version still is not working for you, can you let us know more detail about whats going on so we can help get it working?

    1
  • Comment author
    Mauro Arancibia

    Hey Josh-Lopez

     

    First of all, I appreciate for your fast answer. I already did all the necessary steps. I only need to capture email and memberstack id but I already tried with any other variable such as first-name and last name but didn't go through.

    Does this work for you?

    0
  • Comment author
    Josh Lopez

    I looked at the typeform docs again. Mauro Arancibia does the following work for you? if it doesn't you may need to get additional help by contacting one of our experts here.

    <script>
      // Replace 'qVTlfl9j' with your unique Typeform ID
      const TYPEFORM_ID = 'qVTlfl9j';

      // Configuration map is empty as we only need email and memberstack id
      const TF_CONFIG_MAP = [];

      // Function to generate hidden fields for Typeform based on Memberstack data
      function generateHiddenFields({ config, member }) {
        const fields = [];

        // Add member ID and email to the fields
        fields.push(`memberstack_id=${encodeURIComponent(member.id)}`);
        fields.push(`email=${encodeURIComponent(member.auth.email)}`);
        return fields.join(','); // Join fields into a single string
      }

      // Function to generate the Typeform string with hidden fields
      const GENERATED_TYPEFORM_STRING = (member) => {
        return generateHiddenFields({
          config: TF_CONFIG_MAP,
          member,
        });
      };

      // Function to inject the Typeform widget into the page
      function injectTypeform(member) {
        const tfEl = document.createElement('div'); // Create a new div element
        const anchor = document.getElementById('tf-wrapper'); // Get the anchor element where Typeform will be injected

        tfEl.id = 'tf-form'; // Set the ID of the div element

        // Set Typeform attributes
        tfEl.setAttribute('data-tf-widget', TYPEFORM_ID);
        tfEl.setAttribute('data-tf-inline-on-mobile', true);
        // tfEl.setAttribute('data-tf-hide-headers', true); // Uncomment to hide headers
        tfEl.setAttribute('data-tf-transitive-search-params', true);
        tfEl.setAttribute('data-tf-medium', 'snippet');

        console.log('generated: ', GENERATED_TYPEFORM_STRING(member)); // Log the generated Typeform string
        tfEl.setAttribute('data-tf-hidden', GENERATED_TYPEFORM_STRING(member)); // Set hidden fields
        tfEl.setAttribute('style', 'height:100%'); // Set the height of the div
        tfEl.style.width = '100%'; // Set the width of the div

        anchor.appendChild(tfEl); // Append the Typeform div to the anchor element

        const typeformScript = document.createElement('script'); // Create a new script element
        typeformScript.setAttribute('src', '//embed.typeform.com/next/embed.js'); // Set the source of the script

        document.head.appendChild(typeformScript); // Append the script to the head of the document
      }

      // Get the current Memberstack member and inject the Typeform widget when member data is ready
      window.$memberstackDom.getCurrentMember().then(({ data: member }) => {
        if (member) {
          injectTypeform(member);
        }
      });
    </script>
    0
  • Comment author
    Mauro Arancibia
    • Edited

    Josh-Lopez

    I appreciate it! For some reason is now working but it duplicates the form within the page. I also get email in a different format (without @)

    e.g. contact%40m4uro.com
    instead contact@m4uro.com

     

     

    0
  • Comment author
    Josh Lopez

    Mauro Arancibia You may have a duplicate script for the double form or have two of the same divs for the embed. For the email not being formatted correctly the %40 mean an @ symbol. You may have to adjust for that. Here is additional info.

    0

Please sign in to leave a comment.