{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-embeds/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Embedding forms in Kotlin","description":"Build integrations, automate workflows, and manage forms and responses programmatically with the forms.app API.","siteUrl":"https://developers.forms.app","image":"/assets/formsapp-developer-docs.6ffba4f5ff7d394698661bcdb0ed2a8452f27acaf4e82754e5d0f4109563471c.9c1bb791.png","lang":"en-US","projectTitle":"forms.app Developer Docs","llmstxt":{"sections":[{"title":"llmtxt for forms app documents","includeFiles":["**/*"],"excludeFiles":[]}]},"jsonLd":{"@context":"https://schema.org","@type":"Organization","additionalType":"https://en.wikipedia.org/wiki/Software_as_a_service","url":"https://forms.app","name":"forms.app","logo":"https://cdn.forms.app/icons/all/brands/formsapp-logo-dark.svg","description":"forms.app is a free online form builder designed for teams. forms.app offers a modern, easy-to-use form builder and allows unlimited responses and team members.","foundingDate":"2018","sameAs":"https://linkedin.com/company/formsapp","contactPoint":{"@type":"ContactPoint","contactType":"Customer service","email":"support@forms.app","url":"https://forms.app/en/contact-us"}}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"embedding-forms-in-kotlin","__idx":0},"children":["Embedding forms in Kotlin"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Native Android apps don't have a DOM to embed a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<script>"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["<iframe>"]}," into, so a form is embedded with a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebView"]}," that loads the form's URL, or a small HTML wrapper that carries the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embeds/script-embed"},"children":["script embed"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"webview-embed","__idx":1},"children":["WebView embed"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class CakeOrderFormActivity : AppCompatActivity() {\n    private lateinit var webView: WebView\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        webView = WebView(this)\n        setContentView(webView)\n\n        webView.settings.javaScriptEnabled = true\n        webView.settings.domStorageEnabled = true\n        webView.webChromeClient = WebChromeClient() // required for camera / file-upload fields\n        webView.webViewClient = WebViewClient()\n\n        webView.loadUrl(\"https://eu.forms.app/form/69d4bd130b443bda40c8f65a\")\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["javaScriptEnabled"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["domStorageEnabled"]}," are both required; forms.app forms use JavaScript and local storage."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebChromeClient"]}," is needed for file-upload and camera-based fields to open a native picker inside the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebView"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Request the runtime permissions your form's field types need (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CAMERA"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RECORD_AUDIO"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ACCESS_FINE_LOCATION"]},"), matching the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allow"]}," attribute used on the web ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embeds/iframe-embed"},"children":["iframe embed"]},", and grant ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebView"]}," access to them in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPermissionRequest"]}," on your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebChromeClient"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"manifest-permissions","__idx":2},"children":["Manifest permissions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Only declare the ones your form's field types actually need:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"xml","header":{"controls":{"copy":{}}},"source":"<uses-permission android:name=\"android.permission.INTERNET\" />\n<uses-permission android:name=\"android.permission.CAMERA\" />\n<uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n","lang":"xml"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"passing-data-into-the-form","__idx":3},"children":["Passing data into the form"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The form's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["src"]}," URL doesn't accept prefill query parameters directly; prefilling goes through the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["answers"]}," option of the script embed (see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embeds/passing-form-data"},"children":["Passing data to your form"]},"). To use it from a native app, load a small HTML wrapper containing the script embed instead of loading the form URL directly:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"@Composable\nfun CakeOrderFormScreen(referralCode: String) {\n    val safeReferral = remember(referralCode) {\n        JSONObject.quote(referralCode) // escape for safe interpolation into the HTML string below\n    }\n\n    AndroidView(factory = { context ->\n        WebView(context).apply {\n            settings.javaScriptEnabled = true\n            settings.domStorageEnabled = true\n            webChromeClient = WebChromeClient()\n\n            val html = \"\"\"\n                <html>\n                  <body style=\"margin:0;\">\n                    <div data-formsapp-src=\"https://eu.forms.app/form/69d4bd130b443bda40c8f65a\"></div>\n                    <script src=\"https://cdn.formsapp.io/embed.js\" async defer onload=\"\n                      new formsapp('69d4bd130b443bda40c8f65a', 'standard',\n                        {'width':'100vw','height':'formHeight','answers':{'63ebad419442ad0448b9e9b6':$safeReferral}},\n                        'https://eu.forms.app');\n                    \"></script>\n                  </body>\n                </html>\n            \"\"\".trimIndent()\n\n            loadDataWithBaseURL(\"https://eu.forms.app\", html, \"text/html\", \"UTF-8\", null)\n        }\n    })\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Escape interpolated values"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["referralCode"]}," is being written directly into an HTML string that a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebView"]}," will execute as a page. Always escape or JSON-encode any value that comes from outside your app (a deep link, a previous screen, and so on) before interpolating it, to avoid injecting unintended HTML or script into the page."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["loadDataWithBaseURL"]},"'s ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["baseUrl"]}," argument is set to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://eu.forms.app"]},", your account's data-region domain, so the loaded page resolves the embed script correctly. Match it to the domain shown on your form's Share page."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"whats-next","__idx":4},"children":["What's next"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embeds/embed-options"},"children":["Embed options"]}," for every layout's settings."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embeds/passing-form-data"},"children":["Passing data to your form"]}," for the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["answers"]}," option in full."]}]}]},"headings":[{"value":"Embedding forms in Kotlin","id":"embedding-forms-in-kotlin","depth":1},{"value":"WebView embed","id":"webview-embed","depth":2},{"value":"Manifest permissions","id":"manifest-permissions","depth":3},{"value":"Passing data into the form","id":"passing-data-into-the-form","depth":2},{"value":"What's next","id":"whats-next","depth":2}],"frontmatter":{"seo":{"title":"Embedding forms in Kotlin"}},"lastModified":"2026-08-18T10:33:31.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/embeds/examples/kotlin","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}