REACT
1. Formik
If youβre using React, then you might wanna use a custom form builder like Formik for example.

In order to install Formik to your React project, simply run the following on your Node.js terminal:
npm i formik
Then, insert the following code below to your React project:
Sample Form Code #1
import React from "react"; import ReactDOM from "react-dom"; import { Formik, Field, Form } from "formik"; function App() { }); return ( <div className="App"> <h1>Contact Us</h1> <Formik initialValues={{ name: "", email: "" }} onSubmit={async (values) => { await new Promise((resolve) => setTimeout(resolve, 500)); alert(JSON.stringify(values, null, 2)); }} > <Form> <Field name="name" type="text" /> <Field name="email" type="email" /> <button type="submit">Submit</button> </Form> </Formik> </div> ); } export default App; ReactDOM.render(<App />, document.getElementById("root"));
Sample Form Code #2
import logo from './logo.svg'; import './App.css'; import ReactDOM from "react-dom"; import { Formik, Field, Form } from "formik"; import TagManager from 'react-gtm-module' import React, { Component } from 'react'; export default class FormDataComponent extends Component { render() { return ( <div className="container"> <form onSubmit={this.onSubmit}> <div className="form-group"> <label>Name</label> <input type="text" className="form-control" value={this.state.name} onChange={this.onChangeName} /> </div> <div className="form-group"> <label>Email</label> <input type="email" className="form-control" value={this.state.email} onChange={this.onChangeEmail} /> </div> <div className="form-group"> <label>Phone</label> <input type="tel" className="form-control" value={this.state.phone} onChange={this.onChangePhone} /> </div> <button type="submit" className="btn btn-primary btn-block">Submit</button> </form> </div> ) } }
PIPEDRIVE
Pipedrive uses iframe to embed its form within your website.
What does this mean?
It means your form is not hosted within your own domain hence the data is only stored in their server instead of ours.
This is where the problem starts.

Pipedrive implements a strict cross-origin policy which doesnβt allow any sort of data exchange happening between different domains. This means it will always have to be same-origin every time.
This means if weβre attempting to store any data from their iframe that is actually hosted in Pipedrive.com domain, that tracking script will never be initiated because ourdomain.com is not the same as Pipedriveβs.
Hence, we created this custom form that you can use to still send your form submission data to Pipedrive and while at the same time, installing our conversion snippet to track that form submission if itβs coming from our Partners.
1. Build a Custom Form
Copy this HTML code below:
<form class ="form" onsubmit="return false;"> <input class="form-control" id="firstname_create" name="firstname" placeholder="First Name" required type="text" value=""> <input class="form-control" id="lastname_create" name="lastname" placeholder="Last Name" required type="text" value=""> <input class="form-control" id="username_create" name="username" placeholder="Username" required type="text" value=""> <input class="input form-control" id="email_create" name="email" placeholder="Email" required type="email" value=""> <input class="form-control" id="pwd_create" name="phone" placeholder="phone" required type="phone" value=""> <input type="submit" name="register" id = "myBtn" class="button"> </form>
The form is then going to look like this:

To beautify the form, create a style.css:
body { background: #59abe3; margin: 0; } .form { width: 340px; height: 440px; background: #e6e6e6; border-radius: 8px; box-shadow: 0 0 40px -10px #000; margin: calc(50vh - 220px) auto; padding: 20px 30px; max-width: calc(100vw - 40px); box-sizing: border-box; font-family: "Montserrat", sans-serif; position: relative; } h2 { margin: 10px 0; padding-bottom: 10px; width: 180px; color: #78788c; border-bottom: 3px solid #78788c; } input { width: 100%; padding: 10px; box-sizing: border-box; background: none; outline: none; resize: none; border: 0; font-family: "Montserrat", sans-serif; transition: all 0.3s; border-bottom: 2px solid #bebed2; } input:focus { border-bottom: 2px solid #78788c; } p:before { content: attr(type); display: block; margin: 28px 0 0; font-size: 14px; color: #5a5a5a; } button { float: right; padding: 8px 12px; margin: 8px 0 0; font-family: "Montserrat", sans-serif; border: 2px solid #78788c; background: 0; color: #5a5a6e; cursor: pointer; transition: all 0.3s; } button:hover { background: #78788c; color: #fff; } div { content: "Hi"; position: absolute; bottom: -15px; right: -20px; background: #50505a; color: #fff; width: 320px; padding: 16px 4px 16px 0; border-radius: 6px; font-size: 13px; box-shadow: 10px 10px 40px -14px #000; } span { margin: 0 5px 0 15px; }
Then link this style.css to your HTML code:
<link rel="stylesheet" href="styles.css">
Your form is then going to look something like this:

2. Send Form Data to Pipedrive
Now the next step is you will need to add the following code in order to send your form data upon submission.
1: Add an event listener
To do that, first add an event listener that will listen to your Submit clicks.
// Assigning event listeners to the button let btn = document.getElementById("myBtn"); btn.addEventListener('click', event => { // function goes here });
Then within that event listener, weβll then add a function. Letβs call that function runReditusFunction ()
// Assigning event listeners to the button let btn = document.getElementById("myBtn"); btn.addEventListener('click', event => { runReditusFunction() }); function runReditusFunction(){ if (emailExist()) { sendDatatoPipedrive(); sendDatatoReditus(); } } function emailExist(){ var email_var = document.getElementsByName("email")[0].value; return email_var; } function sendDatatoPipedrive(){ $.ajax({ type: "POST", url: "https://(YOURDOMAINHERE).pipedrive.com/v1/persons?api_token=YOUR_TOKEN_HERE", dataType: 'json', data: { email: emailExist() }})}
Add a listener that will listen to our Button clicks by creating a Trigger.

Add a listener that will listen to your email input within the form. This can be done by adding a Variable within GTM.

2: Establish communication with Pipedrive API
There are 5 steps involved in order to ensure your data appears on:
a) Pipedrive > Persons/Contacts
b) Pipedrive > Leads Inbox

STEP 1
Add this XMLHttpRequest code in order to let your form data be submitted to Pipedriveβs Persons API.
To understand more about their API, read here:
https://developers.pipedrive.com/docs/api/v1/Persons#addPerson
<script> var xhr = new XMLHttpRequest(); xhr.open("POST", 'https://

This will make all form data appear under your Persons API.

STEP 2
If you would like to make the form submission data appear under Leads as well like this below:

You will need to create GET request to fetch the person_id that you created earlier in Step 1 and push that data to a new dataLayer event called βPipedrive Persons APIβ so that we can later fetch it in GTM:
<script> setTimeout(function(){ var xhr = new XMLHttpRequest(); xhr.open("GET",'https://
In order to create a new lead in Pipedrive, a person_id is required because the Persons table is a dependency to their Leads table. A new lead cannot be created if a person_id doesnβt exist or if that lead doesnβt exist as a Person in our Pipedrive Contacts.
Once the data is pushed to GTMβs dataLayer, you can then create a new variable in GTM to make the person_id value readily available for the next API steps.

STEP 3
Once the person_id is stored in the GTM variable youβve created in Step 2 earlier, you can then deploy this script below to post that data back to Pipedrive Leads API so that a new lead record will be created from that person_id.
var xhr = new XMLHttpRequest(); xhr.open("POST", 'https://
STEP 4
Once you create a new lead record via the Leads API, a lead_id will then be generated which will allow us to use it later in Step 5 by sending extra fields like βMessageβ form field that they filled in.
But before we can POST that, we need to GET the lead_id first.
setTimeout(function(){ var xhr2 = new XMLHttpRequest(); xhr2.open("GET",'https://
Follow the same steps like how we create a new GTM variable earlier with Pipedrive Persons ID for Leads ID as well.

STEP 5
Once we have the leads_id, we can then POST the custom Message field values together with the leads_id that we obtain to ensure that for every new lead record weβre adding in Pipedrive, the custom Message will also appear under the Lead Notes section as well.
var xhr = new XMLHttpRequest(); xhr.open("POST", 'https://
3. Add our Conversion Snippet
Then, the final step is to add our conversion snippet.
FIRST METHOD: USING HTML CODE
Remember our code earlier? Add these lines at the bottom of the function:
// Assigning event listeners to the button let btn = document.getElementById("myBtn"); btn.addEventListener('click', event => { runReditusFunction() }); function runReditusFunction(){ if (emailExist()) { sendDatatoPipedrive();
SECOND METHOD: USING GOOGLE TAG MANAGER
Create a tag like this below and add our gr(track) conversion snippet that is triggered when myBtn button id is clicked.

CALENDLY
Calendly uses Embed API to embed its form within your website.
What does this mean?
It means your form is not hosted within your own domain hence the data is only stored in their server instead of ours.
This is where it gets tricky because their Embed API works the same as how an iframe operates.
There are 3 server-side features that Calendly provide which allows us to track any Calendly booking form input:
FIRST FEATURE: window.postMessage()
Calendly JS widget uses window.postMessage()Β to post events to the parent window. The event payload is a JavaScript object of the following format whereΒ XXX
Β is the name of the booking flow event:
{ event: 'calendly.XXX' }
Here are the events Calendly fires when an invitee follows the booking flow:
SECOND FEATURE: CROSS-ORIGIN ALLOW

Unlike some tools, Calendly practices a very relaxed cross-origin policy which allows data resources sharing between different domains.
THIRD FEATURE: WITH CORS ALLOW, THIS MEANS WE CAN LEVERAGE GET API REQUEST

Later in this guide, we are going to show how you can leverage Calendly API in order for you to fetch every successful form submission from Calendly.
Alright, letβs show you the steps based on the 3 server-side features that Calendly is providing us. You may also need to install Google Tag Manager to your site as well in order to make the steps work.
1. Create a JavaScript listener to push Calendlyβs data in window.postMessage() to GTMβs dataLayer
In order to do that, we have built a code that you can use:
<script> window.dataLayer = window.dataLayer ||[]; window.addEventListener('message', function(e) { if (e.data.event && e.data.event.indexOf('calendly') === 0) { window.dataLayer.push({ 'event' : 'calendly', 'calendly_event_name' : e.data.event.split('.')[1], 'calendly_event_details' : e.data.payload, 'calendly_just_invitee' : e.data.payload.invitee.uri, 'calendly_invitee_separate' : e.data.payload.invitee.uri.split('/'), 'calendly_event_uuid' : e.data.payload.invitee.uri.split('/')[4], 'calendly_invitee_uuid' : e.data.payload.invitee.uri.split('/')[6] }); } } ) </script>
Copy the code above and paste it inside a new tag in Google Tag Manager and set it to trigger in All Pages.

Run GTM Debug Console to see the resulting JSON payload:

The only 2 values weβre interested in are the:
Calendly Invite UUID:
Calendly Invitee UUID:
which weβre going to need for our 2nd step.

2. Communicate with Calendly API to fetch email data
Remember the 2 values in the dataLayer earlier? We will now need to store them as GTM variables so that we can use it in our API request that weβre going to do in a bit.
Create the first GTM variable and set the Data Layer Variable Name as calendly_event_uuid

Create the second GTM variable and set the Data Layer Variable Name as calendly_invitee_uuid

Then, create a new Tag in GTM and copy the following code below:
<script> var xhr = new XMLHttpRequest(); xhr.open("GET",'https://api.calendly.com/scheduled_events/{{calendly_event_uuid}}/invitees/{{calendly_invitee_uuid}}', true); xhr.setRequestHeader("Authorization", "Bearer Create your own Calendly API token"); xhr.responseType = 'json'; xhr.onload = function(e) { if (this.status == 200) { console.log('response', this.response); // JSON response window.dataLayer.push({ 'event' : 'API', 'all' : this.response }); } }; xhr.send(); </script>
To make the code work, you will also need to generate your own API token from Calendly > Integration > Webhook:

3. Acquire email data from API response
Now the API will be providing a response like below:
all: { resource: { cancel_url: "https://calendly.com/cancellations/02cf7215-49cc-4" + "e56-9789-d5adafa0fb9c", created_at: "2022-06-17T07:12:42.721529Z",
The only value that weβre interested in is the email value which weβre going to need to trigger our conversion snippet.

Hence, we create another variable in GTM and name the Data Layer Variable: all.resource.email.

And in GTM debug console, it will appear like this:

FOURTH: Include the email data and trigger our conversion snippet
Create a new tag to place our conversion snippet:
gr('track', 'conversion', { email:

Ensure the conversion snippet tag only triggers right after the API response and not before. Hence go back to our XMLHTTPRequest tag that we created earlier and set the trigger scheduling as below:

And then voila! Youβre done!
WORDPRESS
1. Forminator
Firstly, letβs create a GTM variable
First you will need to create a variable in GTM that will listen to email field input within the form.
Go to Variables section.

Create a new variable and input the following code below:
WHAT YOU SHOULD USE
function grabEmailForReditus() { var email_data = document.querySelector('[id^="forminator-field-email-1"]').value; return email_data }

WHAT YOU SHOULD NEVER USE
function grabEmailForReditus() { var email_data = document.
The reason why the code above will never work is because Forminator generates a unique ID for every form submission hence the number becomes dynamic and changes every time which can fail the ability for us to listen to form submissions.

This means the right way to listen isnβt to use getElementById but to use querySelector instead.
Secondly is to create a trigger:
This trigger is for us to time when exactly the email field value that we listen to earlier to be sent back to us.
In GTM, go to Trigger section > Create a new trigger.

Then pick Click - All Elements as the Trigger Type.

Then pick Some Clicks instead of All Clicks followed by inputting the following within Click Classes value:
forminator-button forminator-button-submit
Then hit Save.

Thirdly, letβs create the tags to initiate Reditus Base Script and Conversion Tracking Script.
Reditus Base Tag
Input the following code inside the tag:
<script> (function(w, d, s, p, t) { w.gr = w.gr || function() { w.gr.q = w.gr.q || []; w.gr.q.push(arguments); }; p = d.getElementsByTagName(s)[0]; t = d.createElement(s); t.async = true; t.src = "https://app.getreditus.com/gr.js?_ce=60"; p.parentNode.insertBefore(t, p); })(window, document, "script"); gr("track", "pageview"); </script>

Reditus Conversion Tag
Input the following code below:
<script> gr('track','conversion', {email: {{email_data_var}} }); </script>

2. Elementor
Firstly, letβs create a GTM variable
First you will need to create a variable in GTM that will listen to email field input within the form.
Go to Variables section.

Create a new variable and input the following code below:
WHAT YOU SHOULD USE
function grabEmailForReditus() { var email_data = document.getElementById('form-field-email').value return email_data }

Secondly is to create a trigger:
This trigger is for us to time when exactly the email field value that we listen to earlier to be sent back to us.
In GTM, go to Trigger section > Create a new trigger.

Then pick Click - All Elements as the Trigger Type.

Then pick Some Clicks instead of All Clicks followed by inputting the following within Click Text value:
Click Text value
Then hit Save.
Thirdly, letβs create the tags to initiate Reditus Base Script and Conversion Tracking Script.
Reditus Base Tag
Input the following code inside the tag:
<script> (function(w, d, s, p, t) { w.gr = w.gr || function() { w.gr.q = w.gr.q || []; w.gr.q.push(arguments); }; p = d.getElementsByTagName(s)[0]; t = d.createElement(s); t.async = true; t.src = "https://app.getreditus.com/gr.js?_ce=60"; p.parentNode.insertBefore(t, p); })(window, document, "script"); gr("track", "pageview"); </script>

Reditus Conversion Tag
Input the following code below:
<script>gr('track', 'conversion', { email: {{grabEmailForReditus}} })</script>
PHP
1. PHP Form with JavaScript Function
Assuming you have built a simple PHP form with the following code:
<form action="#" method="post"> <div> <label for="name">Name:</label> <input type="text" name="name" required="required" placeholder="Enter your name" /> </div> <div> <label for="name">Email:</label> <input id="email" type="email" name="email" required="required" placeholder="Enter your email" /> </div> <button type="submit">Subscribe</button> </form>
In order to track the email input and pass it to our conversion tracking snippet, you will need to do the following:
a) Copy the following script below and paste it below the </form>
<script> function validateFormOnSubmit() { var emaildata = document.getElementById("email").value; if (emaildata==emaildata) { gr("track", "conversion", { email: emaildata }); } } </script>
What the script does:
1) First part of the function is to grab the value of the email field after being filled
var emaildata = document.getElementById("email").value;
2) Second part of the function is to tell the code that if the email data exists (when the email field is filled), only then store the data within gr(βtrackβ)
if (emaildata==emaildata) { gr("track", "conversion", { email: emaildata }); } }
b) Then, add the following code at the beginning of the <form> code:
<form action="#" onsubmit="return validateFormOnSubmit();" method="post">
What the script does:
We are trying to tell the code to run the validateFormOnSubmit() function at the point of completion of the form.
Then one last step is remember to add our Reditus Base Tag as well just at the beginning of the <script>:
(function(w, d, s, p, t) { w.gr = w.gr || function() { w.gr.q = w.gr.q || []; w.gr.q.push(arguments); }; p = d.getElementsByTagName(s)[0]; t = d.createElement(s); t.async = true; t.src = "https://app.getreditus.com/gr.js?_ce=60"; p.parentNode.insertBefore(t, p); })(window, document, "script"); gr("track", "pageview");
Finally your code would look something like this:
<form action="#" onsubmit="return validateFormOnSubmit();" method="post"> <div> <label for="name">Name:</label> <input type="text" name="name" required="required" placeholder="Enter your name" /> </div> <div> <label for="name">Email:</label> <input id="email" type="email" name="email" required="required" placeholder="Enter your email" /> </div> <button type="submit">Subscribe</button> </form> <script> (function(w, d, s, p, t) { w.gr = w.gr || function() { w.gr.q = w.gr.q || []; w.gr.q.push(arguments); }; p = d.getElementsByTagName(s)[0]; t = d.createElement(s); t.async = true; t.src = "https://app.getreditus.com/gr.js?_ce=60"; p.parentNode.insertBefore(t, p); })(window, document, "script"); gr("track", "pageview"); function validateFormOnSubmit() { var emaildata = document.getElementById("email").value; if (emaildata==emaildata) { gr("track", "conversion", { email: emaildata }); } }</script>