Typeform and Gravity Forms
Both need the Sourcream script on the page (Custom HTML sites, WordPress). Pages with a Typeform embed also need it loaded with defer (step 3).
Typeform
Typeform embeds run inside an iframe, so no script on your page can fill their fields directly. Typeform's own hidden fields solve this: the embed passes them into the typeform when it loads, and Sourcream sets them for you.
1. Add hidden fields in Typeform
In the Typeform editor, add hidden fields with exactly these names:
first_source, first_medium, first_campaign, last_source, last_medium, last_campaign, sc_visitor_id
(If you renamed fields under the site's Field names in Sourcream, use your names.)
2. Embed with Typeform's embed code
Use Typeform's standard embed (any of data-tf-live, data-tf-widget, data-tf-popup, data-tf-slider, data-tf-popover or data-tf-sidetab). The Sourcream script finds the embed element and sets its data-tf-hidden attribute to first_source=...,first_medium=...,...,sc_visitor_id=..., which Typeform passes into the form.
If your embed already has a data-tf-hidden attribute (for example to pass UTMs), Sourcream leaves it alone. Remove it, or add the Sourcream names to it yourself with values from Sourcream.read().
Links that open typeforms on typeform.com (not embedded) cannot receive the values.
3. Load Sourcream with defer on pages with an embed
Typeform reads data-tf-hidden once, as soon as the page's HTML has finished loading (the DOMContentLoaded event), and ignores any later change. The standard Sourcream tag loads with async, which lets it run after that moment, for example when the script is not cached yet. The embed then starts without the values, and the lead arrives in Sourcream as (direct). Putting the tag in the <head> does not change this.
On every page with a Typeform embed, load the Sourcream script with defer instead of async, in the <head>:
<script src="https://cdn.sourcream.ai/t/YOUR_SITE_KEY.js" defer></script>
A defer script still does not block rendering, and browsers always run it before DOMContentLoaded. The Sourcream script sets data-tf-hidden as soon as it runs, so the values are in place when Typeform reads them. The same applies to the first-party proxy tag: <script src="/_sc/t/YOUR_SITE_KEY.js" defer></script>.
Leave Typeform's own embed.js tag as Typeform supplies it, a plain <script> without async or defer. Typeform then waits for DOMContentLoaded, which comes after Sourcream. If a plugin or page builder adds embed.js with async, or with defer ahead of the Sourcream tag, Typeform can read the attribute before Sourcream has set it.
WordPress plugin. The plugin adds the script with
async. To switch it todefer, add this to a child theme'sfunctions.phpor a code snippets plugin:add_action( 'wp_enqueue_scripts', function () { wp_script_add_data( 'sourcream', 'strategy', 'defer' ); }, 20 );With the script tag in the theme instead (WordPress, option B), write
deferin place ofasyncin the tag.Google Tag Manager. A tag that GTM adds cannot be guaranteed to run before Typeform reads the attribute. On pages with a Typeform embed, put the Sourcream tag in the page itself.
Consent. With consent mode set to Required or Google Consent Mode, Typeform gets the values Sourcream has at the moment Typeform reads them. If the visitor's consent is not known by then, that is this visit only (first touch equals last touch) and an empty visitor ID, and consent given later on the page does not reach the open embed. For a returning visitor who already accepted, make the answer available before the page finishes loading: set
window.SourcreamConsent = truebefore the Sourcream tag, or have the banner push its Consent Modeupdatefrom a script that runs beforeDOMContentLoaded(Consent).Embeds created in your own JavaScript (Typeform's
createWidget,createPopupand similar) have nodata-tf-hiddenattribute for Sourcream to set. Create them once the Sourcream script has run and pass the values in the embed'shiddenoption. With the Sourcream tag loaded withdefer, aDOMContentLoadedhandler is late enough:<div id="contact-typeform"></div> <script src="//embed.typeform.com/next/embed.js"></script> <script> document.addEventListener('DOMContentLoaded', function () { var v = window.Sourcream ? Sourcream.read() : { first: {}, last: {}, visitorId: '' }; window.tf.createWidget('YOUR_FORM_ID', { container: document.getElementById('contact-typeform'), hidden: { first_source: v.first.source, first_medium: v.first.medium, first_campaign: v.first.campaign, last_source: v.last.source, last_medium: v.last.medium, last_campaign: v.last.campaign, sc_visitor_id: v.visitorId } }); }); </script>Do not wait for
Sourcream.ready()here: with a consent mode it only calls back after consent, so the form would not appear for visitors who have not chosen yet.
4. Get the response into Sourcream
Typeform submissions happen inside the iframe, so the Sourcream script does not see them. Send them to Sourcream with Typeform's webhook:
- In Sourcream, copy the site's intake URL (Sites, your site, Webhook intake; shown once, rotate to see a new one).
- In Typeform, open the form's Connect, Webhooks, add the intake URL and turn it on.
Sourcream reads the hidden fields from form_response.hidden, finds the email among the answers, links the lead to the visitor through sc_visitor_id and de-duplicates on Typeform's event_id. The lead then goes to your connected CRM like any other. Typeform's native HubSpot or Salesforce integrations can also map the hidden fields straight into CRM fields if you prefer.
Gravity Forms
Gravity Forms names its inputs by field number (input_4), so Sourcream cannot recognise them by name. Use CSS classes instead.
1. Add hidden fields
For each value, add a Hidden field to the form and set Appearance, Custom CSS Class:
| Field label (your choice) | Custom CSS Class |
|---|---|
| First source | sc-first_source |
| First medium | sc-first_medium |
| First campaign | sc-first_campaign |
| Last source | sc-last_source |
| Last medium | sc-last_medium |
| Last campaign | sc-last_campaign |
| Sourcream visitor ID | sc-sc_visitor_id |
Gravity Forms puts the class on the field's wrapper (.gfield), and the Sourcream script fills the input inside it. If your version does not offer the class on Hidden fields, use a Single Line Text field with Advanced, Visibility set to Hidden and the same class. The values then appear in each entry, in notification emails (merge tags) and in Gravity Forms add-ons such as HubSpot, Salesforce or Zapier.
Gravity Forms' AJAX and multi page forms are fine: the script fills forms rendered after page load too.
2. Lead capture
Each submission is reported to Sourcream from the browser. For server side capture as well, use the Gravity Forms Webhooks add-on:
- Add a webhook feed with your Sourcream intake URL, method POST, format JSON.
- Request Body: Select Fields, and add keys
sc_visitor_id,email,name,phone,company, the six hidden field keys (first_source...), each mapped to its field, andevent_idmapped to the entry ID.
Choosing "All Fields" sends Gravity Forms' field numbers as keys, which Sourcream cannot match; use Select Fields. The browser report and the webhook for the same submission are merged into one lead.
Check it
Submit a test with ?utm_source=test&utm_medium=test&utm_campaign=forms on the page address, then check the Typeform response or Gravity Forms entry for the hidden values and Leads in Sourcream for the lead.
Questions: [email protected]