Overview

These days, it can be hard to promote a web app. Well, we'd be happy to help you with that. Integrate with JotForm and get your web app featured to our 2.5 Million users! Building a JotForm Integrated App is great way to promote your app. We will add your logo and product name on our Form Builder Integrations Wizard.

integration apps

It's easy. We have great tools that make it very easy to implement an integration app. All you need to do is use handle authentication with your app, use our Question Mapper widget to connect form builds to data fields on your app, and setup & handle webhook requests sent from JotForm.

Don't wait. We will be announcing integration apps created to our users by email, blog, twitter and facebook! If you are among the first, you’ll get more exposure and be featured. We’re also running a Developer Competition. Get your app ready by September 24th and become eligible to win the grand award or one of the category awards.

We’re here to help, and we'd love to hear your thoughts. Feel free to email us at api@jotform.com. We'd be happy to help you. We’ll even assign a developer to help you with your integration.

Video Demo

Examples

A complete open-source jotform integrated sample app could be found github or zip archive.

myCRM is a simple web app written in PHP & MySQL. Feel free to install it on your server to start your development with a working codebase.

You can try out a working myCRM app at crm.jotform.io.

----------

A second open-source sample app which integrates Jotform with Getresponse can be found on github

This sample app is built using the Jotform and Getresponse API's and utilizes php, jquery and backbone js.

Tutorial - Creating Your App

This is a step by step tutorial on how to create an integration App.

1. Register your app

Go to My Apps page to begin registering your app. Selecting the correct platform is essential when creating an integration app. When asked to choose your app platform you will need to select Web App from the list, and then select Web Integration from the options that appear below.

2. Choose your app mode

You will then need to select the mode of your integration app. You will have the following choices:

  • Canvas Mode - This mode is fully customizable. All you do is supply Jotform with a Url and you take care of authorization, field matching, and matching form submission data to your users. For more info, see - Canvas app tutorial.

  • Simple Mode - This mode is not customizable, but Jotform will collect and process authorization, field matching, and submission data for you based on the details you provide them with.

3. Enter your app settings

The settings that you are asked to enter will be dependant on the the mode you set for your app.

  • Misc Settings

    • Removal Notification Url (optional) - Do you want Jotform to notify you when a user removes your integration from their form? This can be used for removing settings from your database, removing webhooks, etc. The Url you provide will receive a POST request from Jotform containing the following parameters: formId, username, apiKey.
  • Canvas Mode

    • Canvas Url - The Url that Jotform will serve through an iframe on the integrations wizard. See the tutorial below for more information a setting up your Canvas Page.

  • Simple Mode

    • Authorization
      You will need to authenticate users with you app/service. Jotform will create a authentication form using the details you provide below. Jotform will send a request to the Url you provide to check users authentication. You should return a "SUCCESS" string if users are authenticated.
      • Request Type - The type of request Jotform should send to your authorization Url.

      • Parameters - An array of auth parameters objects. Jotform will use this to create a authentication form for users to fill out.
        E.g [{"name": "username", "label": "Username", "name": "apiKey", "label": Api Key}]

        name: The name of the input
        label: The form label for the input

      • Url - The Url that Jotform will send the user supplied authentication details for you to authenticate users with your app.



    • Data Fields - An array of data field objects for your app. Users will need to map their form fields to your supplied data fields. This will allow Jotform to match the form submissions to your data fields and send the matched data to you.

      E.g : [{"value":"First Name","key":"first_name","type":"control_textbox","autoMatch":0},{"value":"Last Name","key":"last_name","type":"control_textbox","autoMatch":0},{"value":"Email","key":"email","type":"control_email","autoMatch":1}]

      For a more detailed explanation please refer to Question Mapper documentation.

    • Data Post Url - The Url where Jotform where will send the matched submission data.

4. Create your canvas (Canvas mode apps only)

If you are creating a canvas app, you will need to create a canvas page to display in the Jotform integrations wizard. Please refer to the Canvas app tutorial below.


5. Check your app on the Jotform Form Builder

Go to jotform.com. On form builder, click "Integrations" button via the "Setup & Embed" tab on the toolbar. You should see a tab titled My Apps. Click that tab to see if your app name and app image show up on that page.

Now, if you click your app icon, it will open another modal box. Your canvas URL will be shown within the iFrame. Jotform issues a POST request to your canvas URL with the following parameters:

Tutorial - Creating Your Canvas App

If you have chosen a canvas app for your integration app

1. Set up your canvas Url

Your canvas Url is the page users are shown when they choose to integrate a form with your app or service. This url will be loaded through an iframe inside in Jotform integrations wizard.

When this happens Jotform instantly issue a POST request to your canvas Url with the following parameters:

  • formId - The id of the current form, for which the integration is set being set up.
  • apiKey - A "full access" apiKey for the current users account. Use this to perform Jotform api requests on behalf of the current user.
  • username - The Jotform username of current user. You may use this to help identify current user.

You should capture these POST parameters for later usage. Here an example:

       <?php
          $formId = $_POST["formId"];
          $username = $_POST["username"];
          $apiKey = $_POST["apiKey"];
       ?>
    

2. Authenticate the user to your app

Your next step is to authenticate the user of your app so that you can identify who should receive the data that will be sent by JotForm.

It is up to you how you authenticate the users. You can do it by simply rendering a login dialog box to user, or by giving the user the option to register with your service. Remember, you have to know the app user id of the user in order to complete integration. In our example app, we have simple login box to authenticate.


3. Show Question Mapper Widget to map your app's fields to user's form fields

What your app is trying to achieve is the population of your backend with the submitted form data received from the JotForm webhook. You have to identify which questions on the form will be connected to which fields within your own app database.

Let's give you an example: suppose that your app has a contacts database table having following fields:

  • first_name
  • last_name
  • email
  • location
  • comments

You may initiate Jotform Question Mapper widget with the following code

            //initialize jotform js sdk for integration apps,
            JF.connect({
                apiKey : apiKey,
                formId: formId
            });

            //boot fieldMatcher on given element
            JF.fieldMatch({
                el : document.getElementById("fieldMatcher"),
                targetFields : [
                    {
                        value: "First Name",
                        key : "first_name",
                        type:"control_textbox",
                        autoMatch:true
                    },
                    {
                        value: "Last Name",
                        key  : "last_name",
                        type :"control_textbox",
                        autoMatch:true
                    },
                    {
                        value: "Email",
                        key : "email",
                        type:"control_email",
                        autoMatch:true
                    },
                    {
                        value: "Address",
                        key : "location",
                        type:"control_adress",
                        autoMatch:true
                    },
                    {
                        value: "Comments",
                        key : "comments",
                        type:"control_textbox",
                        autoMatch:true
                    },
                ],
                callback : function(m){
                    //we have matches go step3
                    matches = m;
                    step3();
                }

            });

        

The only catch here is this: the el parameter is the target DOM element where widget is to be rendered. Other than that, complete documentation of Question Mapper can be found on here.

When a user clicks the finish button, you'll receive "matches" on your callback function. Here is a JSON representation of a sample matches javascript object:

            [{
                "key": "first_name",
                "question": {
                    "key": "1",
                    "value": "jotform first name",
                    "type": "control_textbox",
                    "base": {
                        "hint": " ",
                        "labelAlign": "Auto",
                        "name": "jotformFirst",
                        "order": "1",
                        "qid": "1",
                        "readonly": "No",
                        "required": "No",
                        "size": "20",
                        "text": "jotform first name",
                        "type": "control_textbox",
                        "validation": "None"
                    }
                },
                "target": {
                    "value": "First Name",
                    "key": "first_name",
                    "type": "control_textbox",
                    "autoMatch": true
                },
                "qkey": "1"
            }, {
                "key": "last_name",
                "question": {
                    "key": "3",
                    "value": "jotform last name",
                    "type": "control_textbox",
                    "base": {
                        "hint": " ",
                        "labelAlign": "Auto",
                        "name": "jotformLast",
                        "order": "2",
                        "qid": "3",
                        "readonly": "No",
                        "required": "No",
                        "size": "20",
                        "text": "jotform last name",
                        "type": "control_textbox",
                        "validation": "None"
                    }
                },
                "target": {
                    "value": "Last Name",
                    "key": "last_name",
                    "type": "control_textbox",
                    "autoMatch": true
                },
                "qkey": "3"
            }, {
                "key": "email",
                "question": {
                    "key": "4",
                    "value": "jotform email",
                    "type": "control_email",
                    "base": {
                        "confirmation": "No",
                        "confirmationHint": "Confirm Email",
                        "disallowFree": "No",
                        "hint": "ex: myname@example.com",
                        "labelAlign": "Auto",
                        "name": "jotformEmail",
                        "order": "3",
                        "qid": "4",
                        "readonly": "No",
                        "required": "No",
                        "size": "30",
                        "text": "jotform email",
                        "type": "control_email",
                        "validation": "Email"
                    }
                },
                "target": {
                    "value": "Email",
                    "key": "email",
                    "type": "control_email",
                    "autoMatch": true
                },
                "qkey": "4"
            }, {
                "key": "comments",
                "question": {
                    "key": "5",
                    "value": "jotform location",
                    "type": "control_textbox",
                    "base": {
                        "hint": " ",
                        "labelAlign": "Auto",
                        "name": "jotformLocation",
                        "order": "4",
                        "qid": "5",
                        "readonly": "No",
                        "required": "No",
                        "size": "20",
                        "text": "jotform location",
                        "type": "control_textbox",
                        "validation": "None"
                    }
                },
                "target": {
                    "value": "Comments",
                    "key": "comments",
                    "type": "control_textbox",
                    "autoMatch": true
                },
                "qkey": "5"
            }]
        

“Matches” is an array of match objects each representing a map between JotForm form fields and your targetFields.

  • key : key of targetField
  • target : targetField object as you pass to Question Mapper
  • qkey : key of the Jotform form question
  • question : Jotform form question object

So, when you receive a request on your webhook callback url, you'll fetch the matches array and it will create an insert sql statement using it.


4. Store matches on your backend

Now you have received the matches object representing the nature of your integration to JotForm as dictated by the user. You now have to store it so that it can be used in webhooks callback page.

Here is a sample code on how you may store a matches object on a MySQL table:

Here is Javascript code to send matches to backend: (Note: username,myCMUsername and formID are global variables on which you can learn more by looking at the complete canvas url implementation.)

        $.post("save_settings.php",
        {
            matches:JSON.stringify(matches),
            username :myCRMUsername,
            jotUsername : username,
            formId : formId
        },function(resp){
                console.log(resp);
                //call complete to finish this
                JF.complete();
        });
    

Here is the implementation of "save_settings.php" residing at the same directory as canvas url.

        <?php
        //simple php ajax responder for myCRM settings save
        $handle = mysql_connect('YOUR_MYSQL_HOST', "YOUR_MYSQL_USERNAME","YOUR_MYSQL_PASSWORD");
        mysql_select_db("YOUR_MYSQL_DBNAME",$handle);

        $matches = mysql_real_escape_string($_POST["matches"],$handle);
        $formId = mysql_real_escape_string($_POST["formId"],$handle);
        $username = mysql_real_escape_string($_POST["username"],$handle);
        $jot_username = mysql_real_escape_string($_POST["jotUsername"],$handle);

        $query = "insert into settings (username,formId,jot_username,matches) values (
                    '$username',
                    '$formId',
                    '$jot_username',
                    '$matches'
            )";

        $result = mysql_query($query,$handle);
        $output = "OK"; //hope no error occurs here!!!

        mysql_close($handle);
        echo $output;//send username or NOTOK to client

        ?>
    

Remember to replace all the mysql connection parameters with the ones that you use. A link to the mysql table sql dump can be found at the bottom of this page, yet the settings table’s structure is pretty obvious.

5. Create a Webhook

When a submission is made to user's form, the data will be sent to your backend using webhooks. To create a webhook, you must supply a callback url to JotForm API, then every time a form receives a submission, your webhook callback url will receive an HTTP POST request from jotform servers.

You may simply create a webhook using following javascript code:

        //create webhook
        JF.createFormWebhook(formId,webhookUrl,function(){

        },function(){
            alert("error creating webhook");
        });
    

6. Call JF.complete()

So far, you authenticated the user, mapped your fields to a JotForm form questions using question mapper, stored these matches and created a webhook. Now you have to notify JotForm form builder about the status of the process, and tell it to notify the user regarding the completion of the integration process and close the integration modal box. Just use following code and your app is now integrated with JotForm!

        JF.complete();
    

7. Handle webhook callbacks

Here is the complete source code of myCRM webhook callback implementation, written in PHP. It can also be found in the repo

        <?php

        //fetch POST parameters
        $formId = $_POST["formID"];
        $submissionID = $_POST["submissionID"];
        $rawRequest = $_POST["rawRequest"];

        //unescape json encoded rawRequest string
        $escapedRawRequest = unescapeJSON($rawRequest);

        $req = json_decode($escapedRawRequest,true);

        //fetch matches and username from formId inside settings table
        //establish mysql connection
        $handle = mysql_connect('YOUR_MYSQL_HOST', "YOUR_MYSQL_USERNAME","YOUR_MYSQL_PASSWORD");
        mysql_select_db("YOUR_MYSQL_DBNAME",$handle);

        $formId = mysql_real_escape_string($formId,$handle);
        $result = mysql_query("select * from settings where formId = '$formId'",$handle);
        if(mysql_num_rows($result) !== 0){
            //found an entry in settings table belonging to $formId
            $fetch = mysql_fetch_assoc($result);
            $matches = str_replace('\\"', '"', $fetch["matches"]);
            $matches = json_decode($matches);

            $insertValues = array(); //lets populate insert values using matches and rawRequest
            $username = $fetch["username"];

            //find userid
            $sq = "select id from user where username = '".mysql_real_escape_string($username,$handle)."'";
            $sr = mysql_query($sq,$handle);
            $sf = mysql_fetch_assoc($sr);
            $user_id = $sf["id"];

            foreach( $req as $key => $value){
                if(is_array($value) ){
                    foreach($value as $sk => $sv){
                        $search_key = explode("_",$key);
                        $search_key = $search_key[0];
                        $finded = searchFromMatches($matches,$search_key."_".$sk,"true");
                        if($finded !== false){
                            $insertValues[$finded->key] = $sv;
                        }
                    }
                    //handle subfields
                }else{
                    echo "search started => $key \n";
                    $finded = searchFromMatches($matches,$key,"false");
                    if($finded !== false){
                        $insertValues[$finded->key] = $value;
                    }
                }
            }
            //set userid
            $insertValues["user_id"] = $user_id;

            //now we have to insert $insertValues array
            $query = "insert into contacts";
            $keys = array();
            $values = array();

            foreach($insertValues as $key => $value){
                $keys[]=$key;
                $values[]=mysql_real_escape_string($value,$handle);
            }
            //build insert query
            $query = $query." (`".implode("`,`",$keys)."`) values ('".implode("','",$values)."')";
            mysql_query($query,$handle);
            //we are done, record inserted

        }else{
            echo "no integration settings detected";
        }


        //helper functions
        function unescapeJSON($str){
            return str_replace("\\'","'" ,str_replace('\\"', '"', $str));
        }

        function searchFromMatches($matches,$key,$sss){
            if($sss === "false"){
                $key = explode("_", $key);
            }else{
                $key = array($key);
            }
            $key = str_replace("q", "", $key[0]);
            foreach($matches as $match){
                if($match->question->key == $key){
                    return $match->target;
                }
            }
            return false;
        }
        ?>