How to Submit a Gravity Form While Offline

I get requests to build apps with offline form submission every so often, so I thought it would be fun to build one.
In this tutorial I’ll show you how to build a web page on your site that works while offline, and can submit to Gravity Forms on your website when it regains a connection.
You can upload this project to your web server and make a few modifications, and have an offline Gravity Form in no time.

  • HTML, CSS, and JS. No frameworks or dependencies.
  • Progressive web app, in other words a web page that can work offline.
  • Gravity Forms REST API

With this app, you will be able to create a form that will work offline on any device, and save a form submission to send when you go back online.
There isn’t much polish on this, but it works. If you want a more polished version, let me know in the comments.
View this project on Github, or read the tutorial below.


In the demo below, I have the form loaded in the browser and then I turn off my connection and submit the form. You’ll see the message popup, then when I reconnect the form is successfully submitted to my site. This will appear in Gravity Forms under entries.

The entry in WordPress:

How to use this on your site

This project is not exactly drag and drop, but here’s how to use it on your site.
Build Your Form HTML
First, build the form HTML in index.html.
Each field needs to be added, for example if you have an email field you need to add that to index.html. (Technically you only need required fields to submit)
You need to go to your desired Gravity Form to get the correct field IDs. Note: you’ll see field IDs like “input_1_1_3” on your site. You need to remove the first number, so change that to “input_1_3” for the app. I have no idea why.
You can use your web inspector to find these IDs. In the example below, the input ID should be “input_2”.

Next you’ll need to enable the Gravity Forms API and get a url signature.
Visit Gravity Forms settings in your wp-admin, click Web API, and enable.
Visit main.js in the app and change line 6 (app.url) to your website and form ID. For example
var app = {
url: ‘’,
sendLater: false
HTTPS is required for the service worker.
Upload the offline-gravity-form folder to your web server and load it up at
Try it out!
Remember that if you make changes to any files, you need to delete the cache-storage in your browser and reload.

How It’s Done

This is a simple static web page that has an HTML form, and it’s submitted with Javascript.

Offline PWA

I made it work offline by making it a progressive web app, which is done by adding the manifest.json file and service worker (sw.js). The only thing the progressive web app does is cache our files so they work offline, that’s it.
The code is boilerplate, so I’m not going to explain it here.
Important: if you are making changes in development with a service worker registered, the changes will not show up until you delete the cache. Every time you make a change, open Chrome developer tools and go to Application => Cache storage => delete. Then refresh the page.

This project uses offline.js by Hubspot to get more reliable connection information.
Grab the files on Github here.






10 responses to “How to Submit a Gravity Form While Offline”

  1. Wp Developer Avatar

    Thanks Scott For Sharing Gravity Form,Good Tackle.What i Looking For…

  2. Hasse Avatar

    This is exactly what I was looking for! I want an solution for an iPad with frontend input of forms offline. All data should then be sent to a database when there is access to the internet again.

  3. Zachary Avatar

    Hey Scott, really useful stuff here. I am currently using this to create custom posts for a family project. I got everything to work in my setup with the exception of file uploads. I was able add a condition for the file type field and change the data. But GF refuses to accept the data. I tried just the value from the input and the base 64 of the image. Do you know what data is necessary to provide API. This field seems like the least documented field.

    1. Scott Avatar

      I don’t know, sorry. You’d also have to figure out how to save the file while offline, which is tricky because you can’t use browser storage for that.

  4. BerraVV Avatar

    Does this offline upload feature work if I use the form repeatedly (e.g. submit multiple entries of the form, then reconnect to network)? Will it submit all entries, or only one at a time until (re)cffonnecting?
    @Zachary, if the file uploads are live photo, you could workaround the storage issue by timestamping the form submission, then it is possible to match the “submission period” with the “date created” photo properties.
    Also possible to choose your desired file upload and in doing so get grab of its properties (filename) as text data for later recall offline.
    These workaround ideas are easy done on import/export too btw.

    1. Niels Alsted Avatar
      Niels Alsted

      @berraVV did you come up with a solution for multible submissions?
      I am implementing this but has to my horror seen that it only works for one submission pr offline session

      1. Zachary Avatar

        Multiple submissions were stored in an array. I was able to submit them one by one. I had to refactor quite of bit of this code for it to work properly. With file uploads, unfortunately the Gravity Forms API DOES NOT support file uploads 🙁 I was able to create my own endpoint which uploaded images and then attached them to the submission with GF hooks though in a later project. I never went back to add it to that project.
        Here was my code for multiple submissions:
        function readURL(input) {
        ‘use strict’;
        if (input.files && input.files[0]) {
        var file = input.files[0];
        var reader = new FileReader();
        reader.onload = function (base64) {
        document.getElementById(‘bannerImg’).src =;
        function getPhoto( fileName ) {
        ‘use strict’;
        var base64 = localStorage.getItem(‘file’);
        var base64Parts = base64.split(“,”);
        var fileFormat = base64Parts[0].split(“;”)[0].split(“:”)[1];
        var fileContent = base64Parts[1];
        var file = new File([fileContent], fileName, {type: fileFormat});
        return file;
        (function() {
        ‘use strict’;
        //set variables
        var app = {
        url: ‘url/gravityformsapi/forms/2/submissions’,
        photoUrl: ‘url/wp-json/wp/v2/media’,
        sendLater: false
        app.init = function() {
        * attach event listener for when we go from offline back to online
        Offline.on( ‘up’, app.reconnected );
        app.submitForm = function(e) {
        var form = document.getElementById(‘sb_form’);
        var data = {};
        data.input_values = {};
        // loop over form inputs and put them into the right data format
        for (var i = 0; i res.json())
        .then((resJson) => {
        console.log( resJson );
        .catch((error) => {
        app.sendLater = false;
        // send our data to the server. Returns a promise.
        app.sendData = function( data ) {
        return new Promise( function(resolve, reject) {
        var req = new XMLHttpRequest();“POST”, app.url);
        req.onload = function () {
        if (req.readyState === req.DONE) {
        if (req.status === 200) {
        req.send( JSON.stringify( data ) );
        app.sendLater = false;
        // handle the response from the GF API
        app.gfResponse = function( response ) {
        var a = JSON.parse( response );
        if( a.response.validation_messages ) {
        document.getElementById(‘gf-message’).innerHTML = JSON.stringify( a.response.validation_messages );
        } else if( a.response.confirmation_message ) {
        document.getElementById(‘gf-message’).innerHTML = a.response.confirmation_message;
        setTimeout( function() {
        document.getElementById(‘gf-message’).innerHTML = ”;
        }, 7000 );
        * Event listener called when we go from offline back to online
        app.reconnected = function() {
        // send the form we stored offline
        if( app.sendLater === true ) {
        var existingSubmissions = JSON.parse( localStorage.getItem( ‘form_submissions’ ) );
        for ( var submissions = 0; submissions <= existingSubmissions.length; submissions++ ) {
        app.sendData( existingSubmissions[submissions] ).then();
        var existingPhotoSubmissions = JSON.parse( localStorage.getItem( 'photo_submissions' ) );
        for ( var picSubmissions = 0; picSubmissions <= existingPhotoSubmissions.length; picSubmissions++ ) {
        var photoSubmission = JSON.parse( existingPhotoSubmissions[picSubmissions] );
        app.sendPhotoData( photoSubmission ).then();
        window.sbOffline = app;

  5. Saad Avatar

    Hi Scott,
    Thanks for this. Very useful information. I‘m wondering how you managed to submit files via the html form. The code snippet you‘ve posted doesn’t seem to have information regarding the own endpoint you‘ve created. Am I missing something?
    Thank you,

  6. doug Avatar

    Would this allow gravity forms submissions from a static site?

  7. Ewomazino Donald Avatar
    Ewomazino Donald

    Hi Scott
    Could this be packaged into a wp plugin for non techies.
    Let’s discuss more if you or anyone is interested.