LogoLogo
HomeExploreDocsAPIBlogContact
  • Gooey.AI Updates & Blog
  • 🌱Gooey.AI Workflow Accelerator Supported by The Rockefeller Foundation
  • 🎉2025 Gooey.AI Copilot Update
  • Embeddable Web Widget Made With React
  • 🏃‍♀️Handling schema migrations on a live database, at scale
  • AI Workflow Standards
  • 🧩Fun fun functions!
  • 🌼Spring Into Summer With Copilot
  • 🏎️Global Language Understanding for AIs
  • 🍜From Bland to Brilliant ChatBots: New Copilot Features for April 2024!
  • 🎉The 2023 Gooey.AI Recap
  • 🤯The GenAI Marketing Disruption & How GooeyAI Can Help
  • 🍺Heineken / Tiger QR Code Case Study
  • 🙌Gooey.AI's Open Source Vision
  • 🤝How to Use Gooey.AI with Google Colab
  • 🌳Climate-smart practices become more accessible for farmers through Farmer.CHAT
Powered by GitBook
LogoLogo

Home

  • Gooey.AI
  • Explore Workflows
  • Sign In
  • Pricing

Learn

  • Docs
  • Blog
  • FAQs
  • Videos

Developers

  • How-to Guides
  • Get your Gooey.AI Key
  • Github
  • API Endpoints

Connect

  • Book a Demo
  • Discord
  • Team
  • Jobs

©2024 by Gooey.AI / Dara.network Inc / support@gooey.ai

On this page
  • Copilot Integration
  • Copilot's Integration UI
  • Widget Code: React and Modern Web Technologies
  • Injection: Shadow DOM Integration

Was this helpful?

Embeddable Web Widget Made With React

Last updated 4 months ago

Was this helpful?

At Gooey.AI, we have an awesome tool - . It lets users create and use an AI-powered chatbot on many different platforms, such as WhatsApp, Facebook, and Slack. Alternatively, they can use the API provided by Gooey.AI to use the chatbot in any application.

However, we wanted to take things a little further to help people/organizations build and deploy AI chatbots faster without relying on any code!

So, we made our own Web Widget Integration which enables our users to deploy a AI-powered chatbot without any code and make it available to use as a standalone Web App.

Here is a high-level understanding of how we wanted the widget to work, let's break it down into 3 major milestones:

  • Copilot Integration: Create and use the Gooey Copilot integration settings

  • Widget Code: React Components, State Handling, Customization Support, Support integration settings

  • Injection: Process of building and loading the widget on any existing website

Let's dive deeper into how we managed to approach this scenario considering our existing architecture and fit the new code with it to achive a seamles AI-powered chatbot experience.

Copilot Integration

  • To embed the widget we have to paste this code inside the <body> tag of client website:

<div id="gooey-embed"></div>
<script> function onLoadGooeyEmbed() { GooeyEmbed.mount({}); </script>
<script async defer onload="onLoadGooeyEmbed()" src="https://gooey.ai/chat/the-gooeyai-bot-xxx/lib.js"></script>
  • The value of src attribute in the above copied code is another JS script which loads the actual widget configuration made by the user using Copilot integrations UI.

(() => {
  let script = document.createElement("script");
  script.src =
    "https://cdn.jsdelivr.net/gh/GooeyAI/gooey-web-widget@2.1.15/dist/lib.js";
  script.onload = function () {
    window.GooeyEmbed.defaultConfig = {
      mode: "popup",
      branding: {
        fabLabel: "Help",
        showPoweredByGooey: true,
        name: "The Gooey.AI Bot",
        byLine: "By Gooey.AI",
        description:
          "Ask me anything about Gooey.AI. I speak almost every language too, so ask in German, Arabic, etc or send over a code snippet. Please give a \ud83d\udc4d\ud83c\udffd \ud83d\udc4e\ud83c\udffe or fork this recipe by tapping the \ud83c\udf10.",
        conversationStarters: [
          "How do you build an AI Copilot?",
          "How can I improve my AI Animations?",
          "What LLMs do you support in AI Copilot?",
          "How can I upgrade my Gooey Pricing Plan?",
        ],
        photoUrl:
          "https://storage.googleapis.com/dara-c1b52.appspot.com/daras_ai/media/371d82e8-1d3c-11ef-b743-02420a000131/Screen%20Shot%202024-05-28%20at%202.49.41%20PM.png",
        websiteUrl:
          "https://gooey.ai/copilot/the-gooeyai-support-bot-3dwfcqvcwl04/",
      },
      showSources: true,
      autoPlayResponses: true,
      enablePhotoUpload: false,
      enableAudioMessage: true,
      enableConversations: true,
      target: "#gooey-embed",
      integration_id: "xxx",
    };
  };
  document.body.appendChild(script);

  window.GooeyEmbed = new Proxy(
    {},
    {
      get: function (target, prop) {
        return (...args) => {
          window.addEventListener("load", () => {
            window.GooeyEmbed[prop](...args);
          });
        };
      },
    }
  );
})();

Here, the integration_id (XXXXX) is the primary identifier which is fed to the Gooey Copilot's streaming API and the server then runs the associated Copilot bot with it.

All the other fields in the config object are loaded in the SystemContext which makes sure all the components mutate themselves accordingly.

This allowed us to keep the "code to be copied" very short and encapsulate the implementation of how we are feeding the configuration to the React app which also makes it cleaner.

Copilot's Integration UI

We created this UX which users can access on /copilot page of their bot and easily give the look and feel they want their users to see. You get the "code to be copied" below here in the UI

Widget Code: React and Modern Web Technologies

  • Add a nice UI/UX for our chat window

  • Make the new components reusable so they can be used ultimately in the future inside gooey-gui

  • Create an open-source example repository showcasing how to leverage Gooey.AI API services in a production grade application framework which is popular around frontend devs these days.

We chose React with Vite.js for our implementation, leveraging Vite.js powerful module bundling and TypeScript support. We wanted to keep things modular component wise as these components would also benefit our core UI application.

The core of our widget revolves around two primary React Contexts:

  • Manages widget-level interactions such as:

    • Minimizing widget

    • Toggling sidebar visibility

    • Activating/deactivating focus mode

    • Supplying copilot integration config to all components

  • Handles chat-related functionalities:

    • Managing message history

    • Sending and receiving messages

    • Integrating with the Gooey Copilot Streaming API

LLM Output Showcase

To render the output by the LLM we used some npm packages:

Keeping it short and optimized!

As it is a widget and has to be downloaded on the clients' site each time the page loads, we had to make sure that the bundle size should be optimized. We are currently at ~520kb unzipped. To achieve this:

  • Introduced a custom CSS framework imitating Bootstrap classes, reduced to only required ones

  • For Icons, we kept SVG code from FontAwesome to avoid downloading entire library.

Injection: Shadow DOM Integration

To embed the React App into any other website we came up with this code.

import { CopilotConfigType } from "./contexts/types";
import { renderCopilotChatWidget } from "./widgets";

interface CopilotEmbedConfig extends CopilotConfigType {
  target: string;
}

declare global {
  var gooeyShadowRoot: ShadowRoot | null;
}

class GooeyEmbedFactory {
  defaultConfig = {};
  _mounted: { innerDiv: HTMLDivElement; root: any }[] = [];

  mount(config: any) {
    config = { ...this.defaultConfig, ...config } as CopilotEmbedConfig;
    const targetElem = document.querySelector(config.target);
    if (!targetElem) {
      throw new Error(
        `Target not found: ${config.target}. Please provide a valid "target" selector in the config object.`
      );
    }
    if (!config.integration_id) {
      throw new Error(
        `Integration ID is required. Please provide an "integration_id" in the config object.`
      );
    }
    const innerDiv = document.createElement("div");
    innerDiv.style.display = "contents";
    if (targetElem.children.length > 0)
      targetElem.removeChild(targetElem.children[0]);
    targetElem.appendChild(innerDiv);
    const root = renderCopilotChatWidget(innerDiv, config);
    this._mounted.push({ innerDiv, root });

    // Global reference to the inner document
    globalThis.gooeyShadowRoot = innerDiv?.shadowRoot;
  }

  unmount() {
    for (const { innerDiv, root } of this._mounted) {
      root.unmount();
      innerDiv.remove();
    }
    this._mounted = [];
  }
}

const GooeyEmbed = new GooeyEmbedFactory();
(window as any).GooeyEmbed = GooeyEmbed;
export default GooeyEmbed;

Our widget's injection process leverages Shadow DOM to create an isolated, encapsulated rendering environment.

Key Injection Capabilities

  • Dynamic target element selection.

  • Configuration validation.

  • Seamless widget embedding.

  • Clean unmounting support.

Shadow DOM Benefits

  • Completely isolate widget styles and DOM.

  • Prevent style conflicts with host website.

  • Ensure widget's CSS doesn't leak or get overridden.

  • Create a secure, independent rendering context.

We are completely open source, so at any point if you may have any suggestions we would appreciate a "Happy" Pull Request from you.

Our Github - https://github.com/GooeyAI

Web Widget Repository - https://github.com/GooeyAI/gooey-web-widget

Our CTO came up with this simple and seamless solution to configure the widget to support the customized widget configurations:

We have our own python UI library which uses React with Remix.js to render the Gooey components. We wanted to:

SystemContext -

MessagesContext -

html-react-parser -

marked -

Written by , Software Engineer, Gooey.AI

@devxpy
gooey-gui
see code
see code
https://www.npmjs.com/package/html-react-parser
https://www.npmjs.com/package/marked
Anish Saxena
Copilot Builder
Demo of our Web Widget with Sources