<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: campaign360</title>
    <description>The latest articles on DEV Community by campaign360 (@campaign360).</description>
    <link>https://dev.to/campaign360</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4090460%2F46844fbf-c1f3-4234-a460-f61894f90718.png</url>
      <title>DEV Community: campaign360</title>
      <link>https://dev.to/campaign360</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/campaign360"/>
    <language>en</language>
    <item>
      <title>How I Built a Free, Client-Side SEO Log Analyzer with Web Workers (No Data Upload, No Limits)</title>
      <dc:creator>campaign360</dc:creator>
      <pubDate>Sun, 23 Aug 2026 06:29:11 +0000</pubDate>
      <link>https://dev.to/campaign360/how-i-built-a-free-client-side-seo-log-analyzer-with-web-workers-no-data-upload-no-limits-154</link>
      <guid>https://dev.to/campaign360/how-i-built-a-free-client-side-seo-log-analyzer-with-web-workers-no-data-upload-no-limits-154</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Free, Client-Side SEO Log Analyzer with Web Workers
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;No data upload. No limits. No signup. Runs entirely in your browser.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Technical SEOs know server logs are the &lt;strong&gt;ground truth&lt;/strong&gt; for crawl behavior. Search Console shows sampled data. Crawlers simulate. But logs? Logs show exactly what Googlebot, Bingbot, GPTBot, and 80+ other crawlers actually requested.&lt;/p&gt;

&lt;p&gt;The problem: existing tools are either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-priced&lt;/strong&gt; (Botify, OnCrawl, JetOctopus)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desktop-only with limits&lt;/strong&gt; (Screaming Frog Log File Analyser: €99/yr, 1k lines free)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud-based&lt;/strong&gt; (your logs leave your machine)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Solution: 100% Client-Side
&lt;/h2&gt;

&lt;p&gt;I built a free alternative that runs entirely in the browser using &lt;strong&gt;Web Workers&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;‼️ &lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/" rel="noopener noreferrer"&gt;https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Screaming Frog + Log Comparison&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upload both, see gap analysis side-by-side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Crawl Budget by Bot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Googlebot, Bingbot, GPTBot, ClaudeBot, PerplexityBot + 80 more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Crawl Budget by Section&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where bots spend time on your site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spoofer Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reverse DNS + ASN verification for fake crawler UAs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI vs Search Comparison&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;See how AI crawlers differ from search crawlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSV Exports&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bots, wasted URLs, robots.txt recommendations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Daily Trends&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crawl-over-time charts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Technical Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────┐
│        Main Thread (UI)             │
│  - File input / drag-drop           │
│  - Results rendering                │
│  - Chart.js visualizations          │
└────────────────────────────────────────────────┘
               │ postMessage()
               ▼
┌────────────────────────────────────────────────────┐
│      Web Worker (Parser)            │
│  - Streams file in chunks           │
│  - Parses Apache/Nginx/IIS/JSON     │
│  - Classifies 196+ bot patterns     │
│  - Aggregates metrics               │
└──────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Web Workers?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large logs (100MB+) don't block UI&lt;/li&gt;
&lt;li&gt;Streaming parsing = constant memory&lt;/li&gt;
&lt;li&gt;Multi-threaded = faster than single-threaded JS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bot Detection Logic
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified: 196 patterns across 20+ LLM platforms&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BOT_PATTERNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;googlebot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/Googlebot/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;gptbot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/GPTBot/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;claude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/ClaudeBot/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;perplexity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/PerplexityBot/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 190+ more&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Verification: IP → reverse DNS → ASN match&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rDNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;reverseDNS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lookupASN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;KNOWN_RANGES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nf"&gt;ipInRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;asnMatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Supported Log Formats
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Apache Combined / Common&lt;/li&gt;
&lt;li&gt;Nginx access logs&lt;/li&gt;
&lt;li&gt;IIS / W3C Extended&lt;/li&gt;
&lt;li&gt;JSON (Cloudflare Logpush, AWS CloudFront)&lt;/li&gt;
&lt;li&gt;Gzipped (.gz) - decompressed in-browser via &lt;code&gt;pako&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Privacy-First Design
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data upload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero - all parsing local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None - close tab, data gone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;External calls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only optional per-IP reverse DNS check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None on tool page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Crawl budget optimization&lt;/strong&gt; - Find 404/redirect waste by section&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI crawler audit&lt;/strong&gt; - Are GPTBot/ClaudeBot hitting your money pages?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spoofer blocking&lt;/strong&gt; - Identify fake Googlebot IPs for firewall rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migration monitoring&lt;/strong&gt; - Compare pre/post logs for crawl changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orphan page discovery&lt;/strong&gt; - URLs in logs but not in SF crawl&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Export Screaming Frog: &lt;code&gt;Internal → All → Export CSV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Download server logs: Apache &lt;code&gt;/var/log/apache2/access.log&lt;/code&gt;, Nginx &lt;code&gt;/var/log/nginx/access.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Drag both to: &lt;a href="https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/" rel="noopener noreferrer"&gt;https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click "Try sample log" if you want to test first&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Historical comparison (upload multiple date ranges)&lt;/li&gt;
&lt;li&gt;[ ] robots.txt tester integration&lt;/li&gt;
&lt;li&gt;[ ] IndexNow submission from findings&lt;/li&gt;
&lt;li&gt;[ ] API for automated monitoring&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Feedback Welcome
&lt;/h2&gt;

&lt;p&gt;Built this because I couldn't justify €99/yr for occasional log analysis. If you're a technical SEO, developer, or run a large site — try it and tell me what's missing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/" rel="noopener noreferrer"&gt;https://campaign360.io/tools/free-seo-crawl-and-log-file-analyzer/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Contact:&lt;/strong&gt; &lt;a href="mailto:arun@campaign360.io"&gt;arun@campaign360.io&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: #seo #webdev #javascript #webworkers #technicalseo #loganalysis #crawlbudget&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seowebdevjawebworkersvascript</category>
    </item>
  </channel>
</rss>
