How to use external apps to power custom widgets in Duda

March 31, 2020
0 minute read

 

Digital agencies, web professionals and SaaS companies all choose Duda to power their customers’ online presence for a variety of reasons, but one of the most common is undoubtedly the flexibility of the platform. Duda provides all kinds of fantastic native widgets for our customers to use right out of the box, but at the end of the day, what we really want is to empower our partners to build anything their customers need using whatever workflows are most comfortable to them. Sometimes this means using Duda’s custom widget builder , sometimes it means working with our REST API , and sometimes it means building an external app. Let’s explore that last one.


What is an external app?


As you (hopefully, or we should really talk to the marketing team) know, Duda offers a unique custom widget builder that allows developers to build entirely new widgets and integrate 3rd-party solutions directly inside Duda. When you build a custom widget in Duda, the JavaScript for that widget lives in a single function. This code must be maintained as part of the custom widget and can only be updated within the Duda widget builder. For most widgets, this works perfectly fine. However, this can pose challenges for a widget that require a significant amount of JavaScript. This is where you can use an external app to manage the logic of your custom widget.


External apps allow the behavior and logic of custom widgets to be developed and hosted outside the widget builder, while allowing any configuration required in the operation of the widget to still reside within the native Duda platform UI. This offers the best of both worlds — a first-class developer experience when creating the widget and a native Duda look-and-feel when your users add or configure the widget on their websites.


When should I use an external app instead of a normal custom widget?


Here are a few use cases in which it makes sense to use an external widget instead of simply building entirely inside the custom widget builder. They are not the only ones, but these should give you a good idea of how this tool can benefit your team.


  • The widget you’re building necessitates a large amount of JavaScript — more than could be comfortably programmed within the widget builder’s JavaScript panel.
  • You want to use your own IDEs, build process or external source control for the widget code. For instance, if you want to transpile TypeScript or ECMAScript to a JavaScript version available in all your target browsers or store the widget’s source in your company’s GitHub account.
  • You have an existing embeddable application you wish to re-purpose as a Duda widget.


Are there any trade-offs when using an external app to power a widget?


Not really. The most important thing to remember when building external apps for Duda widgets is it puts more of the onus to maintain the widget on your team. 


Here are a few reasons why:


  • The JavaScript source code for your widget must be hosted by your organization outside of Duda, and you will be responsible for keeping the source available.
  • Building and deploying new versions of the source code are the responsibility of your organization, and can’t be initiated through the Duda editor.
  • The Duda editor will no longer hold backups of the previous versions of your code.


As the Peter Parker principle states, ‘with great power comes great responsibility.”


How do I implement an external app in the widget builder


The first step in setting up an external app with Duda is to execute the renderExternalApp method provided by the API object in the widget builder to point to the URL of your external app’s source. This is the only code required to be input into the JavaScript panel of the widget builder. 


Here's the JavaScript:

JavaScript

 

/* 

* Initialization function, called by the renderExternalApp function to lazy load your script

* @param {string} scriptSrc - Full URL of your built script

* @param {object=} container - DOM reference of the widget root

* @param {object=} props - configuration object supplied to your widget

* @param {object=} options - options needed when rendering a non-amd built widget

*/

api.scripts.renderExternalApp(<scriptSrc>, <container>, <props>, <options>)


Example of passing the element parameter from the widget builder function into the renderExternalApp method to be used by the external app.


Here is a brief explanation of each argument:


  • scriptSrc – The URL of your built widget src code. The source code must be hosted on a secure (https) domain. Complex applications should have their script built as a single file. This file will be lazy loaded into the site at runtime.
  • container – A reference to the DOM element into which the widget will be rendered. This reference is passed to you by the widget builder as the element parameter and you can simply pass it as an argument into the renderExternalApp method call.
  • props – An object of configuration data needed by your widget. This can be static values specified by the developer within the widget builder, global Duda data (such as siteId) provided by the data parameter in the widget builder, or specific configuration data provided by the data.config property entered by the user of the widget in the editor. See the developer documentation for a complete breakdown of available properties on the data object.
  • options – If your widget has not been built with an external tool such as Webpack, or was not built as amd you should provide the options argument with both name and amd properties: { amd: false, name: ‘my-widget-name’ }. See our developer documentation on external apps for more information.
 
Example passing configuration data to the external application.


Setting up the external app JavaScript


The basis of external apps are two functions for initialization and cleanup. The renderExternalApp method expects both of these functions to exist in your built source code. If you are using a build system utilizing modules don’t forget to export both these functions so they are available for execution. The functions will be passed an object containing the container, props and options specified in the widget builder.


Here's the JavaScript:



JavaScript

 

/* 

 * Initialization function, called by the renderExternalApp function to lazy load your script

 * @param {object} container - reference to DOM element into which the widget will be rendered

 * @param {object} props - props passed into script from the renderExternalApp method

 * @param {object} options - additional rendering options for non AMD built apps 

 */ 

    export function init ({ container, props, options }) {

      // initialization code

    }

    /* It's important to clean up your code as well,

     * Duda sites use Ajax page loading, and memory leaks

     * can occur if you continuously re-initialize applications

     * as the user navigates between pages

     */ 

    export function clean ({ container }) {

      // cleanup code

    }


Working with component-based frameworks



If you are using Vanilla JavaScript or utility libraries the above functions can be used as the entry and exit points of your application. It’s easy to just call additional functions as needed.


To go from pure functions to using components (like in React), you can simply use the container reference provided as a mounting point for your application.


Here's the JavaScript:


JavaScript

 

import React from 'react';

    import ReactDOM from 'react-dom';

    import App from './App';

    /* Using the DOM element passed to our script through the

     * renderExternalApp method as the mounting point of a

     * React application.

     */

    export function init ({ container, props }) {

      ReactDOM.render(<App {...props} />, container);

    }

    /* Using the same DOM reference to clean up our React

     * application when the widget is about to be removed

     * from the screen.

     */

    export function clean ({ container }) {

      React.DOM.unmountComponentAtNode(container);

    }


Working on your application outside of a Duda site


You can use your own HTML scaffold and pass in your own DOM reference or element ID to view your application as you develop it without having to embed the widget into a Duda site.


Here's the HTML:



HTML

 

<!DOCTYPE html>

    <html lang="en">

      <head>

        <meta charset="utf-8" />              

        <title>React App</title>

      </head>

      <body>

        <div id="root"></div>

        <script src="/path/to/script.js" />   

      </body>

    </html>


And here's the JavaScript:



JavaScript

 

export function init({ containerId, container, props }) {

      const parent = container || document.getElementById(containerId);

      ReactDOM.render(<App {...props} />, parent);

    }

    /* Our init function will use the container prop when called

     * through Duda, or the containerId prop when working in dev

     */

    init({

      containerId: 'root',

      props: {

        testProp: 'External Apps are Awesome'

      }

    });


Important note: You must remember to remove the manual call to init before building and deploying your code. If you are using Webpack or another build tool, use an environment flag so that the manual call to init only happens during development.


Here's the JavaScript:



JavaScript

 

if (process.env.NODE_ENV === "development") {

      init({

        containerId: 'root',

        props: {

          testProp: 'External Apps are Awesome'

        }

      });

    }

 
 
 


Pro-tips and useful hints


There are a few important points to remember when building external apps for Duda that will make life easier and more productive for your developers.


  • Build tools like Webpack should be configured to include assets like CSS inline. Otherwise, you’ll have to link to your external CSS within site templates.
  • Create-react-app doesn’t allow you to edit your Webpack configuration without ejecting, but you can use rescript to configure things exactly how you want.
  • If using create-react-app, you should use rescript to configure your output to use the UMD module format. Here is a sample git repo that includes a rescript configuration.


Though external apps are a relatively new technology for Duda, we see it as a big improvement to our platform and believe it will be a real game-changer, especially for our SaaS partners that provide more complex technologies to their customers. For more information on external app development and anything else that has to do with how Duda can take your online presence management to the next level, you can contact me via jason.hummel@duda.co. Documentation for building external apps can be found in Duda’s Developer Portal .


Jason

Jason Hummel

Director of Solution Engineering, Duda

With over 25 years of web development experience, Jason is focused on providing elegant, usable solutions that follow current industry standards.


Did you find this article interesting?


Thanks for the feedback!
By Shawn Davis April 16, 2026
Website builder analysed 69M AI crawler visits across over 850,000 websites in February 2026 to determine key trends and characteristics that increase local AEO
By Shawn Davis April 1, 2026
Core Web Vitals aren't new, Google introduced them in 2020 and made them a ranking factor in 2021. But the questions keep coming, because the metrics keep changing and the stakes keep rising. Reddit's SEO communities were still debating their impact as recently as January 2026, and for good reason: most agencies still don't have a clear, repeatable way to measure, diagnose, and fix them for clients. This guide cuts through the noise. Here's what Core Web Vitals actually measure, what good scores look like today, and how to improve them—without needing a dedicated performance engineer on every project. What Core Web Vitals measure Google evaluates three user experience signals to determine whether a page feels fast, stable, and responsive: Largest Contentful Paint (LCP) measures how long it takes for the biggest visible element on a page — usually a hero image or headline — to load. Google considers anything under 2.5 seconds good. Above 4 seconds is poor. Interaction to Next Paint (INP) replaced First Input Delay (FID) in March 2024. Where FID measures the delay before a user's first click is registered, INP tracks the full responsiveness of every interaction across the page session. A good INP score is under 200 milliseconds. Cumulative Layout Shift (CLS) measures visual stability — how much page elements unexpectedly move while content loads. A score below 0.1 is good. Higher scores signal that images, ads, or embeds are pushing content around after load, which frustrates users and tanks conversions. These three metrics are a subset of Google's broader Page Experience signals, which also include HTTPS, safe browsing, and mobile usability. Core Web Vitals are the ones you can most directly control and improve. Why your clients' scores may still be poor Core Web Vitals scores vary dramatically by platform, hosting, and how a site was built. Some of the most common culprits agencies encounter: Heavy above-the-fold content . A homepage with an autoplay video, a full-width image slider, and a chat widget loading simultaneously will fail LCP every time. The browser has to resolve all of those resources before it can paint the largest element. Unstable image dimensions . When an image loads without defined width and height attributes, the browser doesn't reserve space for it. It renders the surrounding text, then jumps it down when the image appears. That jump is CLS. Third-party scripts blocking the main thread . Analytics pixels, ad tags, and live chat tools run on the browser's main thread. When they stack up, every click and tap has to wait in line — driving INP scores up. A single slow third-party script can push an otherwise clean site into "needs improvement" territory. Too many web fonts . Each font family and weight is a separate network request. A page loading four font files before rendering any text will fail LCP, especially on mobile connections. Unoptimized images . JPEGs and PNGs served at full resolution, without compression or modern formats like WebP or AVIF, add unnecessary weight to every page load. How to measure them accurately There are two types of Core Web Vitals data you should be looking at for every client: Lab data comes from tools like Google PageSpeed Insights, Lighthouse, and WebPageTest. It simulates page loads in controlled conditions. Lab data is useful for diagnosing specific issues and testing fixes before you deploy them. Field data (also called Real User Monitoring, or RUM) comes from actual users visiting the site. Google collects this through the Chrome User Experience Report (CrUX) and surfaces it in Search Console and PageSpeed Insights. Field data is what Google actually uses as a ranking signal — and it often looks worse than lab data because it reflects real-world device and connection variability. If your client's site has enough traffic, you'll see field data in Search Console under Core Web Vitals. This is your baseline. Lab data helps you understand why the scores are what they are. For clients with low traffic who don't have enough field data to appear in CrUX, you'll be working primarily with lab scores. Set that expectation early so clients understand that improvements may not immediately show up in Search Console. Practical fixes that move the needle Fix LCP: get the hero image loading first The single most effective LCP improvement is adding fetchpriority="high" to the hero image tag. This tells the browser to prioritize that resource over everything else. If you're using a background CSS image for the hero, switch it to anelement — background images aren't discoverable by the browser's preload scanner. Also check whether your hosting serves images through a CDN with caching. Edge delivery dramatically reduces the time-to-first-byte, which feeds directly into LCP. Fix CLS: define dimensions for every media element Every image, video, and ad slot on the page needs explicit width and height attributes in the HTML. If you're using responsive CSS, you can still define the aspect ratio with aspect-ratio in CSS while leaving the actual size fluid. The key is giving the browser enough information to reserve space before the asset loads. Avoid inserting content above existing content after page load. This is common with cookie banners, sticky headers that change height, and dynamically loaded ad units. If you need to show these, anchor them to fixed positions so they don't push content around. Fix INP: reduce what's competing for the main thread Audit third-party scripts and defer or remove anything that isn't essential. Tools like WebPageTest's waterfall view or Chrome DevTools Performance panel show you exactly which scripts are blocking the main thread and for how long. Load chat widgets, analytics, and ad tags asynchronously and after the page's critical path has resolved. For most clients, moving non-essential scripts to load after the DOMContentLoaded event is a meaningful INP improvement with no visible impact on the user experience. For websites with heavy JavaScript — particularly those built on frameworks with large client-side bundles — consider breaking up long tasks into smaller chunks using the browser's Scheduler API or simply splitting components so the main thread isn't locked for more than 50 milliseconds at a stretch. What platforms handle automatically One of the practical advantages of building on a platform optimized for performance is that many of these fixes are applied by default. Duda, for example, automatically serves WebP images, lazy loads below-the-fold content, minifies CSS, and uses efficient cache policies for static assets. As of May 2025, 82% of sites built on Duda pass all three Core Web Vitals metrics — the highest recorded pass rate among major website platforms. That baseline matters when you're managing dozens or hundreds of client sites. It means you're starting each project close to or at a passing score, rather than diagnosing and patching a broken foundation. How much do Core Web Vitals actually affect rankings? Honestly, they're a tiebreaker — not a primary signal. Google has been clear that content quality and relevance still dominate ranking decisions. A well-optimized site with thin, irrelevant content won't outrank a content-rich competitor just because its CLS is 0.05. What Core Web Vitals do affect is the user experience that supports those rankings. Pages with poor LCP scores have measurably higher bounce rates. Sites with high CLS lose users mid-session. Those behavioral signals — time on page, return visits, conversions — are things search engines can observe and incorporate. The practical argument for fixing Core Web Vitals isn't just "because Google said so." It's that faster, more stable pages convert better. Every second of LCP improvement can reduce bounce rates by 15–20% depending on the industry and device mix. For client sites that monetize through leads or eCommerce, that's a revenue argument, not just an SEO argument. A repeatable process for agencies Audit every new site before launch. Run PageSpeed Insights and record LCP, INP, and CLS scores for both mobile and desktop. Flag anything in the "needs improvement" or "poor" range before the client sees the live site. Check Search Console monthly for existing clients. The Core Web Vitals report surfaces issues as they appear in field data. Catching a regression early — before it compounds — is significantly easier than explaining a traffic drop after the fact. Document what you've improved. Clients rarely see Core Web Vitals scores on their own. A monthly one-page performance summary showing before/after scores builds credibility and makes your technical work visible. Prioritize mobile. Google uses mobile-first indexing, and field data shows that mobile CWV scores are almost always worse than desktop. If you only have time to optimize one version, do mobile first. Core Web Vitals aren't a one-time fix. Platforms change, new scripts get added, campaigns bring in new widgets. Build the audit into your workflow and treat it like any other ongoing deliverable, and you'll stay ahead of the issues before they affect your clients' rankings. Duda's platform is built with Core Web Vitals performance in mind. Explore how it handles image optimization, script management, and site speed automatically — so your team spends less time debugging and more time building.
By Ilana Brudo March 31, 2026
Vertical SaaS must transition from tools to an AI-powered Vertical Operating System (vOS). Learn to leverage context, end tech sprawl, and maximize retention.
Show More

Latest posts