Build Offline Web Forms with SurveyJS (No Internet Required)
We frequently get asked: 💡 "Can SurveyJS work without an internet connection?" The answer is absolutely yes, and it's more important than you might think.
In general, we see two main groups asking this:
- Field research and data collection companies whose clients operate in remote areas with no internet infrastructure—places where connectivity is limited or completely unavailable.
- Security-conscious enterprises where internet access is restricted or completely prohibited due to compliance, security policies, or air-gapped network environments.
For these scenarios, SurveyJS is a natural fit. SurveyJS form builder can work entirely offline and sync to the server only when needed while retaining full functionality.
In this post, we'll explore how you can integrate SurveyJS form builder into your application running on a client's machine with no internet connection. We'll walk through a live demo built with Preact and demonstrate how easily you can store a survey and its theme locally, no backend required, and sync data when you're ready.
Real-World Use Cases for Offline Form and Survey Builder
Industry | Scenario |
---|---|
Healthcare | Staff create or modify patient intake and diagnostic forms in clinics without internet access. |
Education | Teachers prepare quizzes, feedback forms, or lesson plans in offline environments. |
Events | Organizers adjust registration or feedback forms on-site before or during the event. |
Legal / Compliance | Auditors work with sensitive internal forms in air-gapped environments to meet strict data policies. |
Government | Officials design public service or census forms on secure offline systems. |
Why SurveyJS Is a Perfect Fit for Air-Gapped Networks
SurveyJS Creator is built to help you design, deploy, and run surveys entirely on your device without a constant internet connection. It offers a smooth, local-first experience that lets you:
- Build and edit surveys and forms directly in your browser, no server required.
- Store your surveys and collected data securely using the browser storage options.
- Operate fully offline, so you're never blocked by connectivity issues.
- Sync your survey data and updates back to your server whenever you're ready.
- Integrate SurveyJS easily with any web application framework you use.
This means you get a reliable, flexible offline form and survey builder that adapts to your workflow, wherever you work.
Try the Demo: Offline SurveyJS Survey Creator
We've built an example which demonstrates SurveyJS Creator working entirely offline. The demo includes:
- Full form builder interface powered by SurveyJS Creator (including the Localization and Theme editors)
- Automatic local storage of the survey and theme JSON schemas
- Complete offline functionality (no internet connection required)
- Optional sync capability: uploads to a server when the internet is available
SurveyJS libraries are loaded from local files, so everything runs completely offline. No CDNs. No server requests. Just open the HTML file in your browser and start building.
The application built with Preact for minimal overhead, but the same approach works in React, Vue, Angular, or plain JavaScript.
Complete Offline Functionality
The demo works with zero internet connection. To load SurveyJS resources, download them from npm:
Save them locally to the application folder. Load SurveyJS resources, including localization and themes, from the local app folder as follows:
<script src="./survey.core.js"></script>
<script src="./survey.i18n.js"></script>
<script src="./survey-js-ui.js"></script>
<script src="./themes/index.js"></script>
<script src="./creator-themes/index.js"></script>
<script src="./survey-creator-core.js"></script>
<script src="./survey-creator-core.i18n.js"></script>
<script src="./survey-creator-js.js"></script>
You can now create and design surveys, localize form content, and build custom survey themes—all with your changes automatically saved. Simply close and reopen your browser to pick up right where you left off.
Save Changes to Local Storage
Implement the saveSurveyFunc
function to store the edited survey in localStorage
. When initializing Survey Creator, check whether localStorage
already contains a survey. If it does, restore the survey's JSON schema and assign it to the JSON
property.
const LOCAL_STORAGE_KEY = "localSurveyJSON";
// Restore a saved survey schema
const savedJSON = localStorage.getItem(LOCAL_STORAGE_KEY);
if (savedJSON) {
try {
creator.JSON = JSON.parse(savedJSON);
} catch (e) {
console.warn("Failed to parse saved JSON:", e);
}
}
// Save the survey schema
creator.saveSurveyFunc = (saveNo, callback) => {
try {
const currentJSON = creator.JSON;
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(currentJSON));
isSurveySaved = true;
console.log("Survey saved.");
} catch (e) {
console.error("Failed to save survey JSON:", e);
isSurveySaved = false;
}
markSyncedIfBothSaved();
callback(saveNo, true);
};
Similarly, users can edit a survey theme in the Theme Editor. To persist the theme, implement the saveThemeFunc
function and store the edited theme in localStorage
. On initialization, check if a saved theme exists. If so, restore its JSON schema and assign it to the theme
property.
const THEME_STORAGE_KEY = "localSurveyTheme";
// Restore a saved theme
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY);
if (savedTheme) {
try {
creator.theme = JSON.parse(savedTheme);
} catch (e) {
console.warn("Failed to parse saved theme:", e);
}
}
// Save the theme
creator.saveThemeFunc = (saveNo, callback) => {
try {
const currentTheme = creator.theme;
localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(currentTheme));
isThemeSaved = true;
console.log("Theme saved.");
} catch (e) {
console.error("Failed to save theme:", e);
isThemeSaved = false;
}
markSyncedIfBothSaved();
callback(saveNo, true);
};
By default, the Form Builder displays a Save button that allows users to save edits manually. For convenience, you can enable auto-save by setting the autoSaveEnabled
property to true
. With this setting, the Form Builder automatically calls saveSurveyFunc
or saveThemeFunc
whenever survey or theme setting change, with a default delay of 500 ms. You can adjust this interval using the autoSaveDelay
property.
Storage Synchronization
When internet connectivity is restored, the app can automatically sync local data:
window.addEventListener("online", () => {
const isSynced = localStorage.getItem(SYNCED_FLAG_KEY);
const json = localStorage.getItem(LOCAL_STORAGE_KEY);
const theme = localStorage.getItem(THEME_STORAGE_KEY);
if (isSynced !== "true" && json && theme) {
console.log("Syncing with server...");
sendToServer(JSON.parse(json), theme);
}
});
While our demo uses localStorage
for simplicity, production applications can explore more robust options such as IndexedDB
or integration with backend or cloud APIs.
View Full Code
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>SurveyJS Form Builder (pReact version)</title>
<script src="./survey.core.js"></script>
<script src="./survey.i18n.js"></script>
<script src="./survey-js-ui.js"></script>
<script src="./themes/index.js"></script>
<script src="./creator-themes/index.js"></script>
<script src="./survey-creator-core.js"></script>
<script src="./survey-creator-core.i18n.js"></script>
<script src="./survey-creator-js.js"></script>
<link rel="stylesheet" href="./survey-core.css" />
<link rel="stylesheet" href="./survey-creator-core.css" />
</head>
<body>
<div id="surveyCreatorContainer" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0;"></div>
<script>
const LOCAL_STORAGE_KEY = "localSurveyJSON";
const THEME_STORAGE_KEY = "localSurveyTheme";
const SYNCED_FLAG_KEY = "localSurveySynced";
let isSurveySaved = false;
let isThemeSaved = false;
SurveyCreatorCore.registerCreatorTheme(SurveyCreatorTheme);
SurveyCreatorCore.registerSurveyTheme(SurveyTheme);
const creator = new SurveyCreator.SurveyCreator({
showThemeTab: true,
showTranslationTab: true
});
creator.autoSaveEnabled = true;
// Restore saved JSON
const savedJSON = localStorage.getItem(LOCAL_STORAGE_KEY);
if (savedJSON) {
try {
creator.JSON = JSON.parse(savedJSON);
} catch (e) {
console.warn("Failed to parse saved JSON:", e);
}
}
// Restore theme
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY);
if (savedTheme) {
try {
creator.theme = JSON.parse(savedTheme);
} catch (e) {
console.warn("Failed to parse saved theme:", e);
}
}
function markSyncedIfBothSaved() {
if (isSurveySaved && isThemeSaved) {
localStorage.setItem(SYNCED_FLAG_KEY, "true");
console.log("Both survey and theme saved. Synced flag set.");
} else {
localStorage.setItem(SYNCED_FLAG_KEY, "false");
}
}
// Persist a survey JSON
creator.saveSurveyFunc = (saveNo, callback) => {
try {
const currentJSON = creator.JSON;
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(currentJSON));
isSurveySaved = true;
console.log("Survey saved.");
} catch (e) {
console.error("Failed to save survey JSON:", e);
isSurveySaved = false;
}
markSyncedIfBothSaved();
callback(saveNo, true);
};
// Persist a survey theme
creator.saveThemeFunc = (saveNo, callback) => {
try {
const currentTheme = creator.theme;
localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(currentTheme));
isThemeSaved = true;
console.log("Theme saved.");
} catch (e) {
console.error("Failed to save theme:", e);
isThemeSaved = false;
}
markSyncedIfBothSaved();
callback(saveNo, true);
};
window.addEventListener("online", () => {
const isSynced = localStorage.getItem(SYNCED_FLAG_KEY);
const json = localStorage.getItem(LOCAL_STORAGE_KEY);
const theme = localStorage.getItem(THEME_STORAGE_KEY);
if (isSynced !== "true" && json && theme) {
console.log("Syncing with server...");
sendToServer(JSON.parse(json), theme);
}
});
function sendToServer(surveyData, theme) {
// Simulated async sync
setTimeout(() => {
console.log("Synced survey:", surveyData);
console.log("Synced theme:", theme);
localStorage.setItem(SYNCED_FLAG_KEY, "true");
}, 1000);
}
creator.render("surveyCreatorContainer");
</script>
</body>
</html>
See Also
Refer to the following page for more examples on how to integrate SurveyJS with different backends: