DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • How Agentic AI Is Turning Traditional Automation Into a Tool Layer?
  • Search Is Becoming the Control Plane for AI Agents
  • Your AI Agent Trusts Every Tool It's Ever Been Introduced To; That's the Whole Problem
  • Designing Tool-Calling AI Agents That Survive Production: A LangGraph Approach

Trending

  • I Built a RAG Agent on Azure AI Foundry in an Afternoon. Here's What Nobody Tells You.
  • The Tectonic AI Platform: A Framework for Taming App Sprawl and Data Fragmentation
  • How I Built a Star Wars Grogu Product Research Agent With Codex, Lark, and SerpApi
  • Performance Testing With JMeter Beyond the Basics: Distributed Load, Realistic Profiles, and Identifying Security Bottlenecks
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Building an AI Visibility Checker With Cloudflare Workers (Without a Backend)

Building an AI Visibility Checker With Cloudflare Workers (Without a Backend)

I built six AI visibility tools without a traditional backend, using one Cloudflare Worker to solve CORS while all scoring logic runs client-side in the browser.

By 
Nena Jasar user avatar
Nena Jasar
·
Aug. 06, 26 · Opinion
Likes (0)
Comment
Save
Tweet
Share
118 Views

Join the DZone community and get the full member experience.

Join For Free

I am not a developer. I want to say that upfront, because it changes everything about how you should read this.

I run nenawow.com, a site that reviews AI tools and SEO software. Three years ago I had no SEO background and no coding background either. Last month I shipped six working tools that check AI visibility signals across any website, and they run without a database, without a backend, and without a single line of code I wrote myself.

This is the story of how that actually happened.

Why I Built This

I kept hitting the same wall while testing AI visibility tools for my reviews. Most of them gave you one score and stopped there. A 64 out of 100 tells you something is wrong. It does not tell you what, where, or how long the fix will take.

I wanted something different. Six focused tools, each checking one layer: crawler access, schema, content quality, llms.txt setup. Each one explaining the why behind every failed check, not just the fact that it failed.

The problem was I could not write a single one of them myself.

The Collaboration Model

So I used Claude to architect and write every line of code. I described what I wanted each tool to check and why. Claude researched the technical approach, picked the architecture, and wrote the HTML, CSS, and JavaScript for all six tools plus the hub page that ties them together.

My job was different. I tested everything. I deployed it. I caught what broke. I am the one who used the tools to write my own AI Visibility Benchmark article, scoring nine SEO publishers, so I know firsthand whether the output is trustworthy or not.

That division of labor is the real subject of this article. Not "how I built a Cloudflare Worker." More like: how far can a non-developer get when the architecture decisions are sound and the testing discipline is real.

First Architecture Decision: No Backend

The first real decision was whether these tools needed a backend at all.

Six tools that check live URLs need to fetch data from those URLs. A browser cannot do that directly because of CORS restrictions, the security rules that stop a webpage from freely calling other websites. The standard fix is a backend server that handles the fetch and passes the result back.

A backend means a server to manage, a database maybe, ongoing hosting costs, and a lot more that can break. For one person running a site solo, that is a real cost. The architecture that got picked instead was a single Cloudflare Worker, a small script that runs at the edge and handles the CORS problem without any of that overhead.

Here is the entire proxy. One file, around 35 lines, doing all the cross-origin work for every tool on the site.

JavaScript
 
export default {
  async fetch(request, env, ctx) {
    const corsHeaders = {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type',
    };

    if (request.method === 'OPTIONS') {
      return new Response(null, { headers: corsHeaders });
    }

    const url = new URL(request.url);
    const targetUrl = url.searchParams.get('url');

    if (!targetUrl) {
      return new Response(
        JSON.stringify({ error: 'No URL provided' }),
        {
          headers: {
            ...corsHeaders,
            'Content-Type': 'application/json',
          },
        }
      );
    }

    try {
      const response = await fetch(targetUrl, {
        headers: {
          'User-Agent':
            'Mozilla/5.0 (compatible; AIVisibilityChecker/1.0)',
        },
      });

      const text = await response.text();

      return new Response(
        JSON.stringify({
          content: text,
          status: response.status,
        }),
        {
          headers: {
            ...corsHeaders,
            'Content-Type': 'application/json',
          },
        }
      );
    } catch (error) {
      return new Response(
        JSON.stringify({ error: error.message }),
        {
          status: 500,
          headers: {
            ...corsHeaders,
            'Content-Type': 'application/json',
          },
        }
      );
    }
  },
};


That is the whole backend. It takes a URL as a query parameter, fetches it server-side where CORS does not apply, and hands the raw HTML back as JSON with permissive CORS headers attached. No routing, no auth, no state.

Every tool calls it the same way. Here is the actual fetch from the Content Citability Grader, one of the six tools live on the site:

JavaScript
 
const PROXY = 'https://ai-visibility-proxy.nena46996.workers.dev/';

async function fetchViaProxy(url) {
  const res = await fetch(
    PROXY + '?url=' + encodeURIComponent(url)
  );

  if (!res.ok) {
    throw new Error('Proxy request failed');
  }

  const data = await res.json();

  if (data.error) {
    throw new Error(data.error);
  }

  return data.content || '';
}


One Worker. One URL. Every one of the six tools sends its fetch requests through it. That single decision is why "without a backend" in the title is not a marketing line. The Worker is the only server-side code in the entire system, and it does not know or care which of the six tools called it.

What Almost Went Wrong: I Thought I Needed More

Here is the part developers will recognize. Early on, I assumed something this complex needed a database, somewhere to store results, track usage, log scans.

It did not. Look at what the Worker actually returns: raw HTML, nothing else. No scores, no analysis, no state. All of the actual intelligence, the regex pattern matching that checks for statistics, quotes, heading structure, FAQ schema, author bylines, lives entirely in the browser, in plain JavaScript running on the page itself. The Content Citability Grader scores four categories, Evidence, Structure, Authority, and AI Readability, by pattern-matching the fetched HTML client-side, the moment the response comes back. Nothing gets sent anywhere to be scored. Nothing gets saved after the tab closes.

That split matters. The Worker's only job is solving CORS. The scoring logic, the actual product, runs for free in the visitor's own browser. No signup, no stored results, no database to maintain. That also matches a principle I hold for every tool I build: never hide information behind a signup, and never collect more than you need.

I almost built more than the project needed. The stateless split between fetch and scoring made it unnecessary.

Performance: What I Actually Measured

I do not have lab-grade benchmarks here. What I have is real usage, from running the tools myself while building the AI Visibility Benchmark article, where I tested nine SEO publisher sites through all three relevant tools.

Results typically came back in 2 to 4 seconds per scan. That held steady across all nine sites I tested, regardless of how large or complex the target page was. For a tool fetching live data from an external URL, parsing it, and scoring it in the browser, that is fast enough that nobody using it would call it slow.

The full build, six tools plus the hub page, took three days. Ten-plus hours a day. Most of that time did not go into the Worker setup. It went into the scoring systems, getting the Content Citability Grader's four categories right, getting the Schema Checker's six schema types detecting correctly, and then connecting all six tools into one coherent workflow on the hub page.

Mistakes: The Real Ones

Two things broke during deployment that had nothing to do with the code itself.

The first was Cloudflare. When I went to paste my Worker code into the project window, it would not take. No error message, nothing explained. The project window just kept showing old placeholder code, a default Hello World script, instead of accepting what I pasted. I tried seven times before it finally went through on the eighth attempt. I still do not know exactly what caused the first seven to fail.

The second was WordPress, and this one took longer to figure out. I embedded each tool using a WPCode shortcode inside a Neve theme blank canvas page. After publishing, the live page showed two menus, the tool's own navigation duplicated alongside something from the Neve template. It looked broken even though the underlying tool worked fine.

The fix turned out to be simple once I found it. Go back into the WPCode snippet, resave the exact same code with no changes, then go back to the page using that snippet and update it again. Preview after that, and the duplicate menu was gone. Nothing about the code changed. Something about how WordPress and Neve cached or registered the snippet did not sync correctly the first time around.

Neither of these was a Worker problem or a JavaScript problem. They were platform quirks, the kind of thing no architecture diagram warns you about. The Worker code itself, once it finally deployed, has not needed a single change since. Its only failure path is the try/catch around the fetch, returning a 500 with an error message if the target site does not respond. That has been enough.

Lessons: What I Would Tell Someone Doing This

If I built this again, I would expect the platform friction before the code friction. The actual AI Visibility Checker, Schema Checker, and Content Citability Grader code worked close to correctly the first time, because the architecture was right from the start. What ate the most time was WordPress's caching behavior and Cloudflare's project window silently rejecting my first seven pastes.

I would also tell anyone trying this without a developer background: the architecture decision matters more than your own coding skill. I could not have picked Cloudflare Workers over a traditional backend myself. I would not have known to ask the question. Getting that one decision right early is what let everything after it stay simple.

The thing is, six tools sound like a big project. In practice, it was one architecture decision, repeated six times, with the real time going into getting each tool's scoring logic right rather than fighting infrastructure.

Six tools. Three days. One Worker doing all the work nobody sees.

AI Tool Visibility (geometry)

Opinions expressed by DZone contributors are their own.

Related

  • How Agentic AI Is Turning Traditional Automation Into a Tool Layer?
  • Search Is Becoming the Control Plane for AI Agents
  • Your AI Agent Trusts Every Tool It's Ever Been Introduced To; That's the Whole Problem
  • Designing Tool-Calling AI Agents That Survive Production: A LangGraph Approach

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook