You built a landing page with HTML, CSS, and a bit of JavaScript. It looks good. But now you need analytics to know if anyone visits, a form to capture leads, maybe an AI chatbot to answer questions, and referral tracking to grow your audience. The usual answer is four separate tools, four accounts, four script tags, and a weekend reading docs.

OperatorStack bundles all of this behind a single script tag. You add one line to your page, sprinkle a few HTML attributes, and your static site gets the same tooling as a full-stack app.

Add the OperatorStack script tag to your HTML page to get cookie-free analytics, lead capture forms, AI chat, and referral tracking. No backend, no framework, no build step. Works with any static host.

What You Get

Before touching code, here is what a single OperatorStack integration gives your static page:

  • Analytics that track page views and unique visitors without cookies or consent banners
  • Forms that accept submissions via plain HTML and auto-build their schema from whatever you send
  • AI chat that scans your page content and answers visitor questions conversationally
  • Referral tracking that detects ?ref= links and attributes signups to the person who shared them
  • A unified contact list where every interaction (form, waitlist, chat) links to one person

All of this works on GitHub Pages, Netlify, Vercel, Cloudflare Pages, an S3 bucket, or a folder on shared hosting.

Step-by-Step Setup

1

Add the script tag. Create a project in the OperatorStack dashboard. Copy the script tag from your project settings and paste it before the closing </body> tag:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Landing Page</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <h1>Welcome to My App</h1>
    <p>The best way to do the thing.</p>

    <!-- OperatorStack: one script tag, everything included -->
    <script src="https://operatorstack.dev/os.js" data-project="pk_your_project_key"></script>
  </body>
</html>

That is it for analytics. The script automatically tracks page views and unique visitors as soon as it loads. No cookies, no consent banner, no configuration. Open your OperatorStack dashboard and you will see traffic data within seconds.

2

Add a lead capture form. Create a form in the OperatorStack dashboard (Forms tab, "New Form"). You will get a form key like frm_abc123. Now add a plain HTML form to your page:

<section id="signup">
  <h2>Join the waitlist</h2>
  <form method="POST" action="https://api.operatorstack.com/v1/f/frm_abc123">
    <input type="text" name="name" placeholder="Your name" required />
    <input type="email" name="email" placeholder="you@example.com" required />
    <input type="hidden" name="_redirect" value="https://yoursite.com/thanks.html" />
    <button type="submit">Get Early Access</button>
  </form>
</section>

This form needs zero JavaScript. It submits directly to OperatorStack's public endpoint, which creates a contact, stores the submission, and redirects the visitor to your thank-you page.

Use _redirect to send visitors to a custom thank-you page after submission. Without it, the API returns a JSON response, which is useful for JavaScript-based submissions but not great as a user experience in plain HTML forms.

3

Or use the SDK for a smoother experience. If you want to avoid a full-page redirect and show a success message inline, use the JavaScript SDK that the script tag exposes:

<form id="waitlist-form">
  <input type="text" id="name" placeholder="Your name" required />
  <input type="email" id="email" placeholder="you@example.com" required />
  <button type="submit">Get Early Access</button>
</form>
<p id="success-msg" style="display:none; color:green;">You're on the list!</p>

<script>
  document.getElementById("waitlist-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const name = document.getElementById("name").value;
    const email = document.getElementById("email").value;

    const result = await OperatorStack.joinWaitlist({ name, email });

    document.getElementById("waitlist-form").style.display = "none";
    document.getElementById("success-msg").style.display = "block";
  });
</script>

The OperatorStack.joinWaitlist() method handles the API call and returns the result, including a referral_code you can use for sharing (more on that in step 4).

4

Add referral tracking. The embed script automatically detects ?ref= parameters in the URL. When someone visits yoursite.com/?ref=jane123, the script stores that referral code and attaches it to any subsequent signup. No code needed for detection.

To let users share their referral link after signing up, use the SDK's getShareLinks method:

<div id="share-section" style="display:none;">
  <p>Share your link to move up the list:</p>
  <div id="share-links"></div>
</div>

<script>
  document.getElementById("waitlist-form").addEventListener("submit", async (e) => {
    e.preventDefault();
    const name = document.getElementById("name").value;
    const email = document.getElementById("email").value;

    const result = await OperatorStack.joinWaitlist({ name, email });
    const links = OperatorStack.getShareLinks(result.referral_code, {
      text: "Check out this app!",
    });

    document.getElementById("share-links").innerHTML = `
      <a href="${links.twitter}" target="_blank">Share on Twitter</a> |
      <a href="${links.linkedin}" target="_blank">Share on LinkedIn</a> |
      <a href="${links.email}">Share via Email</a>
    `;
    document.getElementById("waitlist-form").style.display = "none";
    document.getElementById("share-section").style.display = "block";
  });
</script>

getShareLinks() is synchronous and returns ready-to-use URLs for Twitter, LinkedIn, Email, WhatsApp, and a plain copy link. Every signup through a shared link gets attributed to the referrer automatically.

5

Enable AI chat. In your OperatorStack dashboard, go to Chat settings and flip the toggle to enable. OperatorStack scans your page content and builds a knowledge base from it. The chat widget appears automatically on your page, no extra HTML needed.

Visitors can ask questions and get answers drawn from your page content. If the chat captures an email (through its built-in lead capture flow), that person shows up as a contact in your dashboard, linked to the same unified record as any form submissions or waitlist signups.

The chat widget works best when your page has clear, descriptive text. Headings, feature descriptions, pricing details, and FAQs all feed into the chat's knowledge base. The more content on your page, the better the answers.

The Full Page

Here is a complete, working static landing page with everything wired up:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My App</title>
    <style>
      body {
        font-family: system-ui, sans-serif;
        max-width: 640px;
        margin: 0 auto;
        padding: 2rem;
      }
      input,
      button {
        display: block;
        width: 100%;
        padding: 0.5rem;
        margin: 0.5rem 0;
        box-sizing: border-box;
      }
      button {
        background: #22c55e;
        color: white;
        border: none;
        cursor: pointer;
        border-radius: 4px;
      }
      .hidden {
        display: none;
      }
    </style>
  </head>
  <body>
    <h1>My App</h1>
    <p>The easiest way to solve your problem. Join the waitlist for early access.</p>

    <form id="signup-form">
      <input type="text" id="name" placeholder="Your name" required />
      <input type="email" id="email" placeholder="you@example.com" required />
      <button type="submit">Get Early Access</button>
    </form>

    <div id="success" class="hidden">
      <p>You're on the list!</p>
      <p>Share your link to move up:</p>
      <div id="share-links"></div>
    </div>

    <script src="https://operatorstack.dev/os.js" data-project="pk_your_project_key"></script>
    <script>
      document.getElementById("signup-form").addEventListener("submit", async (e) => {
        e.preventDefault();
        const result = await OperatorStack.joinWaitlist({
          name: document.getElementById("name").value,
          email: document.getElementById("email").value,
        });
        const links = OperatorStack.getShareLinks(result.referral_code);
        document.getElementById("share-links").innerHTML =
          `<a href="${links.twitter}" target="_blank">Twitter</a> | ` +
          `<a href="${links.linkedin}" target="_blank">LinkedIn</a> | ` +
          `<a href="${links.email}">Email</a>`;
        document.getElementById("signup-form").classList.add("hidden");
        document.getElementById("success").classList.remove("hidden");
      });
    </script>
  </body>
</html>

That is 40 lines of HTML. No framework, no build step, no backend. You get analytics, waitlist with referral tracking, AI chat, and a unified contact list in your dashboard.

Custom Events

You can also track custom events for button clicks, scroll depth, or anything else:

// Track when someone clicks a pricing link
document.querySelector(".pricing-link").addEventListener("click", () => {
  OperatorStack.trackEvent("clicked_pricing");
});

Custom events appear in your analytics dashboard alongside page views, so you can see which parts of your page drive engagement.

The SDK methods (joinWaitlist, submitForm, trackEvent) internally await the OperatorStack.ready promise, so you can call them immediately after the script tag loads. But if you reference OperatorStack before the script has loaded, you will get a ReferenceError. Place your code after the script tag or wrap it in a DOMContentLoaded listener.

What You Do Not Need

A quick list of things you can skip when using OperatorStack on a static page:

  • No cookie consent banner. Analytics are cookie-free.
  • No backend. Forms submit directly to OperatorStack's API.
  • No database. Contacts, submissions, and analytics are all stored and queryable in the dashboard.
  • No separate chat tool. The chat widget is included in the same script tag.
  • No referral tracking code. The ?ref= parameter is detected and stored automatically.
  • No build step. Everything works with raw HTML files.

Frequently Asked Questions

Do I need a backend or server to use OperatorStack with a static page?

No. OperatorStack runs entirely from a script tag on your page. Analytics, forms, chat, and referral tracking all work through client-side JavaScript and OperatorStack's hosted API. You can deploy your page on GitHub Pages, Netlify, or any static host.

Does the script tag slow down my page?

The embed script (os.js) is under 10KB gzipped and loads asynchronously. It does not block rendering. Analytics events are batched and sent every 5 seconds to minimize network overhead.

Can I use OperatorStack with a site builder like Carrd or Webflow?

Yes. Any platform that lets you add a custom script tag will work. Paste the script tag into your site's head section or custom code area. Forms work with plain HTML action attributes, so they do not require JavaScript.

What happens when someone visits with a referral link?

The embed script automatically detects the ?ref= parameter, stores it in localStorage, and attaches the referral code to any subsequent waitlist signup or form submission. You do not need to write any referral handling code yourself.