\nyou may have a crawlability problem.\nThat does not mean Google can’t render the page. Google can render JavaScript. The issue is that rendering is not the same as clean, fast, reliable discovery. Rendering can be delayed, fail, depend on blocked resources, or be incomplete. Other crawlers may not handle your JavaScript the same way Google does. AI crawlers may be even less patient.\nFor a serious crawlability audit, gather Google Search Console access, a JavaScript-rendering crawler, server logs if available, XML sitemap access, robots.txt access, framework context, deployment context, and a list of priority URLs by business value.\nDon’t audit random URLs first. Audit the pages that make money.\n1. Discovery and Internal Linking\nCrawlers need paths. SPAs often hide those paths behind client-side behavior, especially when navigation is handled with JavaScript instead of normal links.\nCheck:\nImportant pages have unique, crawlable URLs.\nInternal links use standard anchor tags, like .\nNavigation does not rely only on onClick, buttons, spans, or JavaScript-only route changes.\nImportant pages are not only reachable through filters, tabs, search boxes, or infinite scroll.\nPagination uses crawlable URLs where needed.\nFaceted pages that should be indexed have distinct URLs.\nURLs do not rely on hash fragments like #section or old #! patterns for primary page discovery.\nXML sitemaps include canonical, indexable, 200-status URLs.\nSitemap URLs do not require JavaScript execution to become meaningful.\nOrphan pages are identified, especially product, service, blog, and comparison pages.\nBad pattern:\nPricing\nBetter pattern:\nPricing\nThis sounds basic, but it breaks all the time. If crawlers can’t find the URL, they can’t rank the URL. If AI systems can’t discover the page, they can’t use it as a source.\n2. Raw HTML vs Rendered HTML\nThis is the heart of JavaScript crawlability. You need to know what exists before JavaScript runs and what only appears after rendering.\nCheck:\nThe raw HTML contains the main topic of the page.\nThe primary heading is present in the initial HTML.\nCore body copy is present without waiting for client-side rendering.\nInternal links are visible in raw HTML or reliably available after render.\nProduct, service, pricing, author, FAQ, and location content is not hidden behind inaccessible API calls.\nThe rendered HTML does not remove important content from the initial HTML.\nThe page still makes sense if JavaScript execution is delayed.\nThe first meaningful content is not just a blank shell, loading spinner, or placeholder.\nLook for missing H1s, intro copy, product descriptions, pricing details, reviews, FAQ content, internal links, breadcrumbs, schema markup, canonicals, and robots directives.\nIf the rendered page is strong but the raw HTML is empty, you may need server-side rendering, static generation, pre-rendering, or a framework-level fix.\n3. Rendering and Hydration Risks\nHydration is where a server-rendered or pre-rendered page becomes interactive. It’s also where SEO signals can quietly break.\nCheck:\nServer-rendered content matches client-rendered content.\nHydration does not erase headings, body copy, links, or schema.\nThe app does not flash one version of metadata and then replace it with another.\nClient-side state does not rewrite canonical tags incorrectly.\nLazy-loaded components containing SEO-critical content are rendered early enough to be seen.\nError states are not served to bots because of blocked APIs or missing headers.\nImportant content is not dependent on user interaction.\nRendering does not require cookies, local storage, or logged-in state for public pages.\nPages do not produce different SEO-critical output across refreshes.\nA common failure mode: the page appears server-rendered, but hydration fails. Users still see something, so nobody panics. But crawlers may see broken, incomplete, or inconsistent markup.\nThat’s the kind of issue that wastes weeks because everyone says, “It works on my machine.” Maybe it does. Your machine isn’t the crawler.\n4. Metadata and Robots Directives\nMetadata gets messy in SPAs because the client app often controls the document head. Titles, descriptions, canonicals, robots tags, and social metadata may be injected, changed, or removed after load.\nCheck:\nEach indexable page has a unique in the initial HTML.\nEach indexable page has a relevant meta description in the initial HTML.\nCanonical tags are present and correct before client-side JavaScript changes the page.\nRobots meta tags are correct in raw HTML.\nThere is no accidental noindex in the initial HTML.\nJavaScript does not remove or rewrite robots directives after load.\nOpen Graph and social tags are correct where sharing matters.\nMetadata templates are not producing duplicated titles across thousands of URLs.\nRoute changes update metadata correctly without polluting indexable URLs.\nError pages, filtered pages, and parameter URLs have intentional indexation rules.\nBe especially careful with noindex. If the raw HTML includes a noindex tag and JavaScript removes it later, you’re playing with fire.\n5. Canonicals and Duplicate URL Control\nSingle page applications can create duplicate or near-duplicate URL patterns without anyone noticing. The app may treat multiple routes as the same page. Search engines may not.\nCheck:\nCanonicals point to the preferred URL.\nCanonicals are not injected late in a way that creates inconsistent signals.\nParameter URLs are handled intentionally.\nTrailing slash rules are consistent.\nHTTP and HTTPS versions are consolidated.\nwww and non-www versions are consolidated.\nUppercase and lowercase URL variants do not create duplicates.\nFiltered or sorted versions are indexable only when they should be.\nClient-side routing does not generate multiple paths for the same content.\nCanonical tags match sitemap URLs where appropriate.\nIn a SPA SEO audit, canonicals are not just another checkbox. They help stop your routing system from creating a duplicate-content mess.\n6. Structured Data and Entity Clarity\nStructured data helps machines understand what a page is about. That matters for traditional search, rich results, and AI visibility.\nCheck:\nJSON-LD schema is present in the initial HTML where possible.\nSchema matches visible page content.\nProduct, Article, FAQ, Breadcrumb, Organization, LocalBusiness, SoftwareApplication, or Review schema is used only where appropriate.\nJavaScript does not inject schema too late or remove it during hydration.\nSchema is not duplicated across routes.\nRequired and recommended fields are not empty.\nEntity names are consistent across page copy, schema, headings, and metadata.\nBreadcrumb schema matches visible breadcrumbs.\nFAQ schema, if used, matches visible FAQ content.\nStructured data is tested on both raw and rendered versions.\nDo not use schema as decoration. Use it to clarify what already exists on the page.\n7. AI Crawlability, AEO, and GEO\nAI search adds another layer to crawlability. Traditional SEO already requires pages to be discoverable, renderable, and trustworthy.\nAEO and GEO raise another question: can AI systems extract useful answers, entities, and citations from your site without fighting your front end?\nCheck:\nCritical content is available in the initial HTML through SSR, SSG, or reliable pre-rendering.\nPages answer clear questions in plain language.\nImportant entities are named consistently.\nProduct, service, feature, audience, location, and pricing information is not hidden behind interactions.\nFAQs are visible on-page, not only injected after user action.\nInternal links help crawlers understand topical relationships.\nSchema supports the visible content.\nPages are not blocked for non-Google crawlers unless intentional.\nrobots.txt does not accidentally block resources required to understand the page.\nKey content can be extracted without clicking, scrolling forever, or running complex JavaScript.\nMany SPA teams assume “Google can render JavaScript” means everyone can. That is not a safe assumption. For AI visibility, your safest content is content that is easy to fetch, parse, and understand.\n8. robots.txt, Status Codes, and Crawl Access\nBefore blaming rendering, make sure crawlers are allowed to access the site in the first place.\nCheck:\nrobots.txt does not block important pages.\nrobots.txt does not block CSS or JavaScript files needed for rendering.\nAPI endpoints needed to render public content are not blocked if crawlers depend on them.\nImportant URLs return 200 status codes.\nRedirect chains are cleaned up.\nBroken routes do not return soft 404s with 200 status codes.\nReal 404 pages return 404 status codes.\nProtected or private app routes are not accidentally indexable.\nStaging or preview environments are not indexed.\nProduction pages are not carrying staging noindex rules.\nJavaScript sites often blur the line between “the route exists in the app” and “the server returns a valid page.” Search engines care about both.\n9. Core Web Vitals and Performance\nPerformance is not just a Lighthouse score. It affects crawling, user experience, and conversion.\nCheck:\nJavaScript bundles are not excessively large.\nUnused JavaScript is reduced where possible.\nMain content is not delayed by heavy client-side rendering.\nLargest Contentful Paint is not slowed by app shell rendering.\nInteraction to Next Paint is not hurt by long JavaScript tasks.\nThird-party scripts are not blocking important rendering.\nImages are optimized and not dependent on late client-side loading.\nFonts do not cause major layout shifts.\nLazy loading does not hide important content from crawlers.\nCore Web Vitals are reviewed for priority templates, not just the homepage.\nA SPA can feel fast to your team and still be slow for SEO. If your JavaScript takes too long to deliver the message, the page loses twice: once in search and once in conversion.\n10. UX and Conversion Risks\nA SPA SEO audit should not stop at indexability. If a page gets traffic but fails to convert, the business still loses.\nCheck:\nThe main value proposition is visible without waiting for full app hydration.\nCalls to action appear early and work reliably.\nForms do not break when JavaScript errors occur.\nPricing, demo, signup, or checkout paths are crawlable and usable.\nError states are clear and recoverable.\nPage copy explains what the product or service does without relying on animations.\nNavigation is understandable without app-specific behavior.\nMobile users can access the same core content.\nTracking scripts do not slow the page or interfere with rendering.\nConversion pages are not accidentally noindexed.\nThe goal is not a green score. The goal is a page that can be found, understood, trusted, and acted on.\n11. Framework and Architecture Review\nDifferent JavaScript setups create different SEO risks. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. But you need to know how each important page is being delivered.\nCheck:\nThe rendering mode is known for each important template.\nServer-side rendering, static generation, client-side rendering, or pre-rendering is documented.\nDevelopers and SEO teams agree which pages must be indexable.\nPublic marketing pages are not treated like logged-in app screens.\nFramework upgrades are tested for rendering changes.\nRoute-level metadata is tested after deployments.\nBuild changes do not accidentally remove pre-rendered content.\nAPI failures do not produce thin indexable pages.\nError boundaries do not hide content from crawlers.\nSEO checks are included before major releases.\nThe exact fix depends on the stack. The audit pattern stays the same: prove what crawlers get, then fix the gap.\n12. Google Search Console Checks\nGoogle Search Console will not tell you everything, but it will show useful symptoms.\nCheck:\nImportant URLs are indexed.\nImportant URLs are not stuck in “Discovered, currently not indexed” without explanation.\nImportant URLs are not excluded by noindex.\nGoogle’s selected canonical matches your intended canonical.\nCrawled pages show the expected content.\nPage indexing reports are reviewed by template type.\nSitemap submissions match your indexable URL strategy.\nPerformance data is reviewed for pages that should drive revenue.\nQuery data is checked for technical GEO, AEO, and crawlability demand.\nDrops are compared against deployments, migrations, and framework changes.\nTreat Search Console as evidence, not a magic oracle. If impressions are weak, pages are excluded, or Google chooses unexpected canonicals, your JavaScript delivery may be part of the problem.\n13. Log File and Bot Behavior Review\nIf you have log access, use it. Logs show what crawlers actually did.\nCheck:\nGooglebot is crawling important URLs.\nImportant sections are not being ignored.\nCrawl frequency changed after a migration or release.\nBots are hitting redirected or broken routes too often.\nServer responses for crawlers are clean and consistent.\nStatic assets needed for rendering are accessible.\nNon-Google crawlers are not accidentally blocked if AI visibility matters.\nCrawl waste is reduced on low-value routes.\nMoney pages receive crawl attention.\nBot behavior aligns with your sitemap and internal linking strategy.\nLogs are useful because they show reality: not what the crawler could do, not what the framework should do, but what actually happened.\n14. Copy and Content Extraction\nJavaScript SEO is not only technical. Once crawlers reach the page, they still need meaningful content.\nCheck:\nThe page clearly states what the company, product, or service does.\nThe target audience is obvious.\nThe problem, solution, and outcome are explained.\nImportant terms are written naturally in visible copy.\nHeadings describe the page, not just marketing slogans.\nFeature descriptions are not hidden inside components that require JavaScript to populate.\nFAQs answer real buyer or technical questions.\nComparison and alternative pages include enough context to be useful.\nThin pages are improved or removed from indexation.\nAI extraction would produce an accurate summary of the page.\nCrawlability gets the page seen. Good copy gets the page understood. Clear conversion paths get the buyer moving. You need all three.\n15. CI and Release Monitoring\nA one-time audit helps. A repeatable process protects you from regressions.\nCheck:\nPriority URLs are tested before major releases.\nRaw HTML snapshots are compared over time.\nRendered HTML snapshots are compared over time.\nMetadata changes are monitored.\nCanonical changes are monitored.\nRobots directives are monitored.\nSchema presence is tested.\nInternal links are crawled after deployments.\nPerformance regressions are flagged.\nSEO-critical templates have QA requirements.\nJavaScript SEO problems often appear after innocent changes: a route refactor, framework upgrade, hydration fix, analytics script, redesign, CMS change, or deployment config update. None of those sound like SEO projects. They can still break SEO.\nHow Savage Audit Fits Naturally\nSavage Audit is built for exactly this kind of problem.\nJavaScript-heavy websites usually sit between three teams:\nDevelopers care about architecture, deployment, performance, and maintainability.\nSEO teams care about crawlability, indexation, rankings, and structured data.\nFounders and marketers care about pipeline, demos, signups, and revenue.\nEveryone can be right and the site can still be broken.\nSavage Audit helps identify JavaScript crawlability problems, single page application SEO issues, raw HTML vs rendered HTML gaps, metadata and canonical failures, AI crawlability risks, technical SEO blockers, UX problems, copy gaps, and prioritized fixes your dev team can actually use.\nFor related technical checks, see the Technical GEO Audit Checklist, the Website Audit Tool for Developers, and the guide to LLMs.txt vs Robots.txt vs Structured Data.\nThe point is not to shame the stack. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. The point is to stop pretending the browser experience is the same as crawler access.\nFinal Takeaway\nYour single page application can look beautiful in the browser and still be a search liability.\nDo not start with vanity metrics. Do not start by rewriting every headline. Do not assume “Google can render JavaScript” means your crawlability is fine.\nStart with proof.\nCompare raw HTML against rendered HTML. Check internal links. Verify metadata. Test schema. Review robots directives. Look at crawl access. Then check whether AI crawlers can extract the same core content your users see.\nIf bots cannot read your app, buyers may never find it. That is the real JavaScript SEO audit.","wordCount":2959,"about":[{"@type":"Thing","name":"Technical Teardowns"},{"@type":"Thing","name":"Technical SEO & Website Audits"}],"author":{"@type":"Person","name":"SavageAudit Team","knowsAbout":["SEO audits","AI visibility","UX critique","conversion copy"]},"publisher":{"@type":"Organization","@id":"https://savageaudit.com/#organization","name":"SavageAudit","url":"https://savageaudit.com/","logo":{"@type":"ImageObject","url":"https://savageaudit.com/logo.png"}},"mainEntityOfPage":{"@type":"WebPage","@id":"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#webpage"},"articleSection":"Technical Teardowns","keywords":"javascript seo audit, single page application seo, crawlability audit, javascript crawlability, technical seo crawlability, spa seo audit, ai crawlability audit, Technical Teardowns, Technical SEO & Website Audits, SavageAudit","timeRequired":"PT22M"},{"@context":"https://schema.org","@type":"BreadcrumbList","@id":"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://savageaudit.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://savageaudit.com/blog"},{"@type":"ListItem","position":3,"name":"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site","item":"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps"}]},{"@context":"https://schema.org","@type":"FAQPage","@id":"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#faq","isPartOf":{"@id":"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#webpage"},"mainEntity":[{"@type":"Question","name":"What is a JavaScript SEO audit?","acceptedAnswer":{"@type":"Answer","text":"A JavaScript SEO audit checks whether a JavaScript-heavy website can be discovered, rendered, indexed, understood, and ranked by search engines. It compares raw HTML, rendered HTML, metadata, internal links, schema, status codes, performance, and crawl access."}},{"@type":"Question","name":"What is an AI crawlability audit checklist?","acceptedAnswer":{"@type":"Answer","text":"An AI crawlability audit checklist verifies whether AI crawlers and answer engines can extract useful content from your site. It focuses on raw HTML access, clear copy, structured data, crawl permissions, internal links, and whether important content requires complex JavaScript execution."}},{"@type":"Question","name":"How do I check Backbone.js crawlability?","acceptedAnswer":{"@type":"Answer","text":"For Backbone.js crawlability, start with routing and raw HTML. Check whether important URLs return meaningful content on direct server requests, whether internal links use crawlable anchors, and whether metadata is available before client-side DOM manipulation."}},{"@type":"Question","name":"When should I run a SPA SEO audit?","acceptedAnswer":{"@type":"Answer","text":"Run a SPA SEO audit before launches, migrations, redesigns, framework upgrades, and major routing changes. Also run one after unexplained organic traffic drops, indexation problems, canonical issues, or performance regressions."}},{"@type":"Question","name":"Why is my SPA indexed but not ranking well?","acceptedAnswer":{"@type":"Answer","text":"An SPA can be indexed but still rank poorly if crawlers see thin raw HTML, delayed content, weak internal links, slow rendering, inconsistent metadata, or confusing canonicals. Indexing does not prove search engines fully understood the page."}}]}]</script><div class="blog-hero-glow" aria-hidden="true"><span></span><span></span><span></span></div><article class="blog-post-shell"><section class="blog-post-hero" aria-labelledby="blog-post-title"><div class="container blog-post-hero-inner"><nav aria-label="Breadcrumb" class="blog-breadcrumb"><ol><li><a title="Go to SavageAudit home" href="/">Home</a></li><li aria-hidden="true">/</li><li><a title="Go to SavageAudit blog" href="/blog">Blog</a></li><li aria-hidden="true">/</li><li aria-current="page" title="JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site">JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site</li></ol></nav><header class="blog-post-hero-grid"><div class="blog-post-copy"><div class="blog-category-chips" aria-label="Article categories"><span class="badge">Technical Teardowns</span></div><p class="mono blog-post-meta-line"><time dateTime="2026-07-17T12:00:00Z">Jul 17, 2026</time> / <!-- -->22<!-- --> min read</p><h1 id="blog-post-title">JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site</h1><p class="hero-sub">Use this JavaScript SEO audit checklist to check SPA crawlability, raw HTML, rendering, metadata, AI visibility, UX, and conversion risks before rankings suffer.</p><div class="blog-author-share-row"><div class="blog-author-card"><span class="blog-author-avatar" aria-hidden="true">S</span><div><span class="mono blog-author-label">Written by</span><strong>SavageAudit Team</strong><span>Product & Research</span></div></div><div class="blog-share-buttons" aria-label="Share this article"><a aria-label="Share on X" class="blog-share-button" href="https://twitter.com/intent/tweet?text=JavaScript%20SEO%20Audit%20Checklist%20for%20SPAs%3A%20Make%20Sure%20Crawlers%20Can%20Actually%20Read%20Your%20Site&url=https%3A%2F%2Fsavageaudit.com%2Fblog%2Fjavascript-seo-audit-checklist-single-page-apps" rel="noreferrer" target="_blank" title="Share on X">X</a><a aria-label="Share on LinkedIn" class="blog-share-button" href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fsavageaudit.com%2Fblog%2Fjavascript-seo-audit-checklist-single-page-apps" rel="noreferrer" target="_blank" title="Share on LinkedIn">in<span class="sr-only">Share on LinkedIn</span></a><button aria-label="Copy article link" class="blog-share-button" title="Copy article link" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><span class="sr-only">Copy article link</span></button></div></div></div><aside class="blog-article-brief" aria-label="Article brief"><div class="blog-brief-top"><div><span class="mono blog-brief-eyebrow">Article brief</span><h2>Public-proof reading map</h2></div><span class="badge">Audit Intel</span></div><div class="blog-brief-grid"><div class="blog-brief-row"><span class="mono">Category</span><strong>Technical Teardowns</strong></div><div class="blog-brief-row"><span class="mono">Read time</span><strong>22 min</strong></div><div class="blog-brief-row"><span class="mono">Author</span><strong>SavageAudit Team</strong></div><div class="blog-brief-row"><span class="mono">Published</span><strong>Jul 17, 2026</strong></div></div><div class="blog-brief-angle"><span class="mono">SavageAudit angle</span><p>Use the public web like a buyer would: check search, AI answers, social proof, competitor context, and conversion trust in one pass.</p></div></aside></header></div></section><div class="container blog-post-media-shell"><figure class="blog-post-image"><div class="blog-post-image-frame"><img alt="Dark abstract website audit dashboard showing JavaScript crawlability checks and orange warning panels." title="Dark abstract website audit dashboard showing JavaScript crawlability checks and orange warning panels." width="1600" height="900" decoding="async" data-nimg="1" style="color:transparent" src="https://cdn.sanity.io/images/elyr32gq/production/46535ddf9afe2e9a2b8161a0d870b2ace3418e0b-1376x768.jpg?rect=6,0,1365,768&w=1600&h=900&fit=crop&auto=format"/></div></figure></div><div class="container blog-article-layout"><aside class="blog-article-rail blog-article-rail--left"><div class="blog-article-rail-sticky"><section class="blog-reader-rail-panel" aria-label="Article navigation"><div class="blog-progress-client"><section class="blog-reader-progress"><div class="blog-progress-top"><span class="badge">Reading progress</span><span class="mono blog-progress-value">0<!-- -->%</span></div><div class="blog-progress-track" role="progressbar" aria-label="Article reading progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><span class="blog-progress-fill" style="width:0%"></span></div></section><nav class="blog-reader-toc" aria-label="Table of contents"><div class="blog-article-toc-header"><span class="badge">On this page</span></div><div class="blog-article-toc-list"><a href="#short-answer-what-are-you-auditing" title="Jump to Short Answer: What Are You Auditing?" class="blog-article-toc-link" data-active="true" data-level="2" aria-current="location">Short Answer: What Are You Auditing?</a><a href="#who-this-is-for" title="Jump to Who This Is For" class="blog-article-toc-link" data-active="false" data-level="2">Who This Is For</a><a href="#what-to-check-first" title="Jump to What to Check First" class="blog-article-toc-link" data-active="false" data-level="2">What to Check First</a><a href="#1-discovery-and-internal-linking" title="Jump to 1. Discovery and Internal Linking" class="blog-article-toc-link" data-active="false" data-level="2">1. Discovery and Internal Linking</a><a href="#2-raw-html-vs-rendered-html" title="Jump to 2. Raw HTML vs Rendered HTML" class="blog-article-toc-link" data-active="false" data-level="2">2. Raw HTML vs Rendered HTML</a><a href="#3-rendering-and-hydration-risks" title="Jump to 3. Rendering and Hydration Risks" class="blog-article-toc-link" data-active="false" data-level="2">3. Rendering and Hydration Risks</a><a href="#4-metadata-and-robots-directives" title="Jump to 4. Metadata and Robots Directives" class="blog-article-toc-link" data-active="false" data-level="2">4. Metadata and Robots Directives</a><a href="#5-canonicals-and-duplicate-url-control" title="Jump to 5. Canonicals and Duplicate URL Control" class="blog-article-toc-link" data-active="false" data-level="2">5. Canonicals and Duplicate URL Control</a><a href="#6-structured-data-and-entity-clarity" title="Jump to 6. Structured Data and Entity Clarity" class="blog-article-toc-link" data-active="false" data-level="2">6. Structured Data and Entity Clarity</a><a href="#7-ai-crawlability-aeo-and-geo" title="Jump to 7. AI Crawlability, AEO, and GEO" class="blog-article-toc-link" data-active="false" data-level="2">7. AI Crawlability, AEO, and GEO</a><a href="#8-robots-txt-status-codes-and-crawl-access" title="Jump to 8. robots.txt, Status Codes, and Crawl Access" class="blog-article-toc-link" data-active="false" data-level="2">8. robots.txt, Status Codes, and Crawl Access</a><a href="#9-core-web-vitals-and-performance" title="Jump to 9. Core Web Vitals and Performance" class="blog-article-toc-link" data-active="false" data-level="2">9. Core Web Vitals and Performance</a><a href="#10-ux-and-conversion-risks" title="Jump to 10. UX and Conversion Risks" class="blog-article-toc-link" data-active="false" data-level="2">10. UX and Conversion Risks</a><a href="#11-framework-and-architecture-review" title="Jump to 11. Framework and Architecture Review" class="blog-article-toc-link" data-active="false" data-level="2">11. Framework and Architecture Review</a><a href="#12-google-search-console-checks" title="Jump to 12. Google Search Console Checks" class="blog-article-toc-link" data-active="false" data-level="2">12. Google Search Console Checks</a><a href="#13-log-file-and-bot-behavior-review" title="Jump to 13. Log File and Bot Behavior Review" class="blog-article-toc-link" data-active="false" data-level="2">13. Log File and Bot Behavior Review</a><a href="#14-copy-and-content-extraction" title="Jump to 14. Copy and Content Extraction" class="blog-article-toc-link" data-active="false" data-level="2">14. Copy and Content Extraction</a><a href="#15-ci-and-release-monitoring" title="Jump to 15. CI and Release Monitoring" class="blog-article-toc-link" data-active="false" data-level="2">15. CI and Release Monitoring</a><a href="#how-savage-audit-fits-naturally" title="Jump to How Savage Audit Fits Naturally" class="blog-article-toc-link" data-active="false" data-level="2">How Savage Audit Fits Naturally</a><a href="#final-takeaway" title="Jump to Final Takeaway" class="blog-article-toc-link" data-active="false" data-level="2">Final Takeaway</a></div></nav></div></section></div></aside><div class="blog-article-content"><section class="blog-mobile-reader" aria-label="Mobile article navigation"><div class="blog-progress-client"><section class="blog-reader-progress"><div class="blog-progress-top"><span class="badge">Reading progress</span><span class="mono blog-progress-value">0<!-- -->%</span></div><div class="blog-progress-track" role="progressbar" aria-label="Article reading progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><span class="blog-progress-fill" style="width:0%"></span></div></section><nav class="blog-reader-toc" aria-label="Table of contents"><div class="blog-article-toc-header"><span class="badge">On this page</span></div><div class="blog-article-toc-list"><a href="#short-answer-what-are-you-auditing" title="Jump to Short Answer: What Are You Auditing?" class="blog-article-toc-link" data-active="true" data-level="2" aria-current="location">Short Answer: What Are You Auditing?</a><a href="#who-this-is-for" title="Jump to Who This Is For" class="blog-article-toc-link" data-active="false" data-level="2">Who This Is For</a><a href="#what-to-check-first" title="Jump to What to Check First" class="blog-article-toc-link" data-active="false" data-level="2">What to Check First</a><a href="#1-discovery-and-internal-linking" title="Jump to 1. Discovery and Internal Linking" class="blog-article-toc-link" data-active="false" data-level="2">1. Discovery and Internal Linking</a><a href="#2-raw-html-vs-rendered-html" title="Jump to 2. Raw HTML vs Rendered HTML" class="blog-article-toc-link" data-active="false" data-level="2">2. Raw HTML vs Rendered HTML</a><a href="#3-rendering-and-hydration-risks" title="Jump to 3. Rendering and Hydration Risks" class="blog-article-toc-link" data-active="false" data-level="2">3. Rendering and Hydration Risks</a><a href="#4-metadata-and-robots-directives" title="Jump to 4. Metadata and Robots Directives" class="blog-article-toc-link" data-active="false" data-level="2">4. Metadata and Robots Directives</a><a href="#5-canonicals-and-duplicate-url-control" title="Jump to 5. Canonicals and Duplicate URL Control" class="blog-article-toc-link" data-active="false" data-level="2">5. Canonicals and Duplicate URL Control</a><a href="#6-structured-data-and-entity-clarity" title="Jump to 6. Structured Data and Entity Clarity" class="blog-article-toc-link" data-active="false" data-level="2">6. Structured Data and Entity Clarity</a><a href="#7-ai-crawlability-aeo-and-geo" title="Jump to 7. AI Crawlability, AEO, and GEO" class="blog-article-toc-link" data-active="false" data-level="2">7. AI Crawlability, AEO, and GEO</a><a href="#8-robots-txt-status-codes-and-crawl-access" title="Jump to 8. robots.txt, Status Codes, and Crawl Access" class="blog-article-toc-link" data-active="false" data-level="2">8. robots.txt, Status Codes, and Crawl Access</a><a href="#9-core-web-vitals-and-performance" title="Jump to 9. Core Web Vitals and Performance" class="blog-article-toc-link" data-active="false" data-level="2">9. Core Web Vitals and Performance</a><a href="#10-ux-and-conversion-risks" title="Jump to 10. UX and Conversion Risks" class="blog-article-toc-link" data-active="false" data-level="2">10. UX and Conversion Risks</a><a href="#11-framework-and-architecture-review" title="Jump to 11. Framework and Architecture Review" class="blog-article-toc-link" data-active="false" data-level="2">11. Framework and Architecture Review</a><a href="#12-google-search-console-checks" title="Jump to 12. Google Search Console Checks" class="blog-article-toc-link" data-active="false" data-level="2">12. Google Search Console Checks</a><a href="#13-log-file-and-bot-behavior-review" title="Jump to 13. Log File and Bot Behavior Review" class="blog-article-toc-link" data-active="false" data-level="2">13. Log File and Bot Behavior Review</a><a href="#14-copy-and-content-extraction" title="Jump to 14. Copy and Content Extraction" class="blog-article-toc-link" data-active="false" data-level="2">14. Copy and Content Extraction</a><a href="#15-ci-and-release-monitoring" title="Jump to 15. CI and Release Monitoring" class="blog-article-toc-link" data-active="false" data-level="2">15. CI and Release Monitoring</a><a href="#how-savage-audit-fits-naturally" title="Jump to How Savage Audit Fits Naturally" class="blog-article-toc-link" data-active="false" data-level="2">How Savage Audit Fits Naturally</a><a href="#final-takeaway" title="Jump to Final Takeaway" class="blog-article-toc-link" data-active="false" data-level="2">Final Takeaway</a></div></nav></div></section><section class="portable-content" aria-label="Article content"><section class="blog-answer-summary" aria-label="Direct answer"><span class="badge">Short answer</span><p>A JavaScript SEO audit checks whether search engines, AI crawlers, and users can access the same important SPA content. Start by comparing raw HTML, rendered HTML, metadata, internal links, schema, crawl access, and conversion-critical page elements.</p></section><p>A JavaScript SEO audit is a reality check.</p><p>It answers one simple question: <strong>can search engines, AI crawlers, and real users all access the same important content on your JavaScript-heavy website?</strong></p><p>Your site can look perfect in a browser and still be hard for crawlers to discover, render, understand, or trust. If your key content, internal links, metadata, and schema only appear after client-side JavaScript runs, you may not have a content problem. You may have a delivery problem.</p><p>Before you blame rankings, rewrite every headline, or assume the algorithm hates you, check whether crawlers can actually see what you’re trying to rank.</p><h2 id="short-answer-what-are-you-auditing" class="portable-heading portable-heading-h2">Short Answer: What Are You Auditing?</h2><p>A proper <strong>JavaScript SEO audit</strong> compares what a user sees in the browser with what crawlers can access before and after JavaScript rendering.</p><p>You’re looking for five types of problems:</p><ul><li><strong>Discovery gaps:</strong> crawlers can’t find your important URLs.</li><li><strong>Rendering gaps:</strong> raw HTML is empty, thin, or missing key content.</li><li><strong>Metadata issues:</strong> titles, canonicals, robots tags, or schema show up too late or get overwritten.</li><li><strong>AI crawlability risks:</strong> AI crawlers may not execute your JavaScript before extracting content.</li><li><strong>UX and conversion drag:</strong> large bundles, slow rendering, hydration issues, and front-end bugs hurt users too.</li></ul><p>The blunt version: if your single page app makes the browser do all the work, prove bots can still understand the page. Don’t assume it.</p><h2 id="who-this-is-for" class="portable-heading portable-heading-h2">Who This Is For</h2><p>This guide is for teams running JavaScript-heavy websites where organic visibility matters.</p><p>That includes:</p><ul><li><strong>Developers and engineering leads</strong> working with React, Vue, Angular, Next.js, Nuxt, Backbone.js, or custom JavaScript apps.</li><li><strong>Technical founders</strong> who shipped a polished product but can’t figure out why organic traffic, demo requests, or signups are flat.</li><li><strong>SEO teams</strong> responsible for SPA SEO, technical SEO crawlability, AEO, GEO, and AI visibility.</li><li><strong>Growth and marketing teams</strong> who suspect the content isn’t the real issue.</li><li><strong>Agencies and consultants</strong> auditing modern websites where “view source” and “inspect element” tell two very different stories.</li></ul><p>This is not a meta description tune-up. This is a delivery audit.</p><h2 id="what-to-check-first" class="portable-heading portable-heading-h2">What to Check First</h2><p>Pick one important page from your SPA or JavaScript-heavy site. Not a random page. Choose a page that should bring in qualified traffic, such as a product page, service page, pricing page, comparison page, location page, blog post, or use case page.</p><p>Now compare three versions of that page:</p><ol><li><strong>What a normal user sees in Chrome</strong></li><li><strong>What appears in the raw HTML source</strong></li><li><strong>What appears after a rendered crawl or headless browser render</strong></li></ol><p>You’re looking for the gap between them.</p><p>If Chrome shows a full, useful page but the raw HTML looks like this:</p><p><div id="root"></div><br/><script src="/bundle.js"></script></p><p>you may have a crawlability problem.</p><p>That does not mean Google can’t render the page. Google can render JavaScript. The issue is that rendering is not the same as clean, fast, reliable discovery. Rendering can be delayed, fail, depend on blocked resources, or be incomplete. Other crawlers may not handle your JavaScript the same way Google does. AI crawlers may be even less patient.</p><p>For a serious <strong>crawlability audit</strong>, gather Google Search Console access, a JavaScript-rendering crawler, server logs if available, XML sitemap access, robots.txt access, framework context, deployment context, and a list of priority URLs by business value.</p><p>Don’t audit random URLs first. Audit the pages that make money.</p><h2 id="1-discovery-and-internal-linking" class="portable-heading portable-heading-h2">1. Discovery and Internal Linking</h2><p>Crawlers need paths. SPAs often hide those paths behind client-side behavior, especially when navigation is handled with JavaScript instead of normal links.</p><p>Check:</p><ul><li>Important pages have unique, crawlable URLs.</li><li>Internal links use standard anchor tags, like <code><a href="/page"></code>.</li><li>Navigation does not rely only on <code>onClick</code>, buttons, spans, or JavaScript-only route changes.</li><li>Important pages are not only reachable through filters, tabs, search boxes, or infinite scroll.</li><li>Pagination uses crawlable URLs where needed.</li><li>Faceted pages that should be indexed have distinct URLs.</li><li>URLs do not rely on hash fragments like <code>#section</code> or old <code>#!</code> patterns for primary page discovery.</li><li>XML sitemaps include canonical, indexable, 200-status URLs.</li><li>Sitemap URLs do not require JavaScript execution to become meaningful.</li><li>Orphan pages are identified, especially product, service, blog, and comparison pages.</li></ul><p>Bad pattern:</p><p><span onclick="navigate('/pricing')">Pricing</span></p><p>Better pattern:</p><p><a href="/pricing">Pricing</a></p><p>This sounds basic, but it breaks all the time. If crawlers can’t find the URL, they can’t rank the URL. If AI systems can’t discover the page, they can’t use it as a source.</p><h2 id="2-raw-html-vs-rendered-html" class="portable-heading portable-heading-h2">2. Raw HTML vs Rendered HTML</h2><p>This is the heart of <strong>JavaScript crawlability</strong>. You need to know what exists before JavaScript runs and what only appears after rendering.</p><p>Check:</p><ul><li>The raw HTML contains the main topic of the page.</li><li>The primary heading is present in the initial HTML.</li><li>Core body copy is present without waiting for client-side rendering.</li><li>Internal links are visible in raw HTML or reliably available after render.</li><li>Product, service, pricing, author, FAQ, and location content is not hidden behind inaccessible API calls.</li><li>The rendered HTML does not remove important content from the initial HTML.</li><li>The page still makes sense if JavaScript execution is delayed.</li><li>The first meaningful content is not just a blank shell, loading spinner, or placeholder.</li></ul><p>Look for missing H1s, intro copy, product descriptions, pricing details, reviews, FAQ content, internal links, breadcrumbs, schema markup, canonicals, and robots directives.</p><p>If the rendered page is strong but the raw HTML is empty, you may need server-side rendering, static generation, pre-rendering, or a framework-level fix.</p><h2 id="3-rendering-and-hydration-risks" class="portable-heading portable-heading-h2">3. Rendering and Hydration Risks</h2><p>Hydration is where a server-rendered or pre-rendered page becomes interactive. It’s also where SEO signals can quietly break.</p><p>Check:</p><ul><li>Server-rendered content matches client-rendered content.</li><li>Hydration does not erase headings, body copy, links, or schema.</li><li>The app does not flash one version of metadata and then replace it with another.</li><li>Client-side state does not rewrite canonical tags incorrectly.</li><li>Lazy-loaded components containing SEO-critical content are rendered early enough to be seen.</li><li>Error states are not served to bots because of blocked APIs or missing headers.</li><li>Important content is not dependent on user interaction.</li><li>Rendering does not require cookies, local storage, or logged-in state for public pages.</li><li>Pages do not produce different SEO-critical output across refreshes.</li></ul><p>A common failure mode: the page appears server-rendered, but hydration fails. Users still see something, so nobody panics. But crawlers may see broken, incomplete, or inconsistent markup.</p><p>That’s the kind of issue that wastes weeks because everyone says, “It works on my machine.” Maybe it does. Your machine isn’t the crawler.</p><h2 id="4-metadata-and-robots-directives" class="portable-heading portable-heading-h2">4. Metadata and Robots Directives</h2><p>Metadata gets messy in SPAs because the client app often controls the document head. Titles, descriptions, canonicals, robots tags, and social metadata may be injected, changed, or removed after load.</p><p>Check:</p><ul><li>Each indexable page has a unique <code><title></code> in the initial HTML.</li><li>Each indexable page has a relevant meta description in the initial HTML.</li><li>Canonical tags are present and correct before client-side JavaScript changes the page.</li><li>Robots meta tags are correct in raw HTML.</li><li>There is no accidental <code>noindex</code> in the initial HTML.</li><li>JavaScript does not remove or rewrite robots directives after load.</li><li>Open Graph and social tags are correct where sharing matters.</li><li>Metadata templates are not producing duplicated titles across thousands of URLs.</li><li>Route changes update metadata correctly without polluting indexable URLs.</li><li>Error pages, filtered pages, and parameter URLs have intentional indexation rules.</li></ul><p>Be especially careful with <code>noindex</code>. If the raw HTML includes a <code>noindex</code> tag and JavaScript removes it later, you’re playing with fire.</p><h2 id="5-canonicals-and-duplicate-url-control" class="portable-heading portable-heading-h2">5. Canonicals and Duplicate URL Control</h2><p>Single page applications can create duplicate or near-duplicate URL patterns without anyone noticing. The app may treat multiple routes as the same page. Search engines may not.</p><p>Check:</p><ul><li>Canonicals point to the preferred URL.</li><li>Canonicals are not injected late in a way that creates inconsistent signals.</li><li>Parameter URLs are handled intentionally.</li><li>Trailing slash rules are consistent.</li><li>HTTP and HTTPS versions are consolidated.</li><li>www and non-www versions are consolidated.</li><li>Uppercase and lowercase URL variants do not create duplicates.</li><li>Filtered or sorted versions are indexable only when they should be.</li><li>Client-side routing does not generate multiple paths for the same content.</li><li>Canonical tags match sitemap URLs where appropriate.</li></ul><p>In a SPA SEO audit, canonicals are not just another checkbox. They help stop your routing system from creating a duplicate-content mess.</p><h2 id="6-structured-data-and-entity-clarity" class="portable-heading portable-heading-h2">6. Structured Data and Entity Clarity</h2><p>Structured data helps machines understand what a page is about. That matters for traditional search, rich results, and AI visibility.</p><p>Check:</p><ul><li>JSON-LD schema is present in the initial HTML where possible.</li><li>Schema matches visible page content.</li><li>Product, Article, FAQ, Breadcrumb, Organization, LocalBusiness, SoftwareApplication, or Review schema is used only where appropriate.</li><li>JavaScript does not inject schema too late or remove it during hydration.</li><li>Schema is not duplicated across routes.</li><li>Required and recommended fields are not empty.</li><li>Entity names are consistent across page copy, schema, headings, and metadata.</li><li>Breadcrumb schema matches visible breadcrumbs.</li><li>FAQ schema, if used, matches visible FAQ content.</li><li>Structured data is tested on both raw and rendered versions.</li></ul><p>Do not use schema as decoration. Use it to clarify what already exists on the page.</p><h2 id="7-ai-crawlability-aeo-and-geo" class="portable-heading portable-heading-h2">7. AI Crawlability, AEO, and GEO</h2><p>AI search adds another layer to crawlability. Traditional SEO already requires pages to be discoverable, renderable, and trustworthy.</p><p>AEO and GEO raise another question: <strong>can AI systems extract useful answers, entities, and citations from your site without fighting your front end?</strong></p><p>Check:</p><ul><li>Critical content is available in the initial HTML through SSR, SSG, or reliable pre-rendering.</li><li>Pages answer clear questions in plain language.</li><li>Important entities are named consistently.</li><li>Product, service, feature, audience, location, and pricing information is not hidden behind interactions.</li><li>FAQs are visible on-page, not only injected after user action.</li><li>Internal links help crawlers understand topical relationships.</li><li>Schema supports the visible content.</li><li>Pages are not blocked for non-Google crawlers unless intentional.</li><li>robots.txt does not accidentally block resources required to understand the page.</li><li>Key content can be extracted without clicking, scrolling forever, or running complex JavaScript.</li></ul><p>Many SPA teams assume “Google can render JavaScript” means everyone can. That is not a safe assumption. For AI visibility, your safest content is content that is easy to fetch, parse, and understand.</p><h2 id="8-robots-txt-status-codes-and-crawl-access" class="portable-heading portable-heading-h2">8. robots.txt, Status Codes, and Crawl Access</h2><p>Before blaming rendering, make sure crawlers are allowed to access the site in the first place.</p><p>Check:</p><ul><li>robots.txt does not block important pages.</li><li>robots.txt does not block CSS or JavaScript files needed for rendering.</li><li>API endpoints needed to render public content are not blocked if crawlers depend on them.</li><li>Important URLs return 200 status codes.</li><li>Redirect chains are cleaned up.</li><li>Broken routes do not return soft 404s with 200 status codes.</li><li>Real 404 pages return 404 status codes.</li><li>Protected or private app routes are not accidentally indexable.</li><li>Staging or preview environments are not indexed.</li><li>Production pages are not carrying staging <code>noindex</code> rules.</li></ul><p>JavaScript sites often blur the line between “the route exists in the app” and “the server returns a valid page.” Search engines care about both.</p><h2 id="9-core-web-vitals-and-performance" class="portable-heading portable-heading-h2">9. Core Web Vitals and Performance</h2><p>Performance is not just a Lighthouse score. It affects crawling, user experience, and conversion.</p><p>Check:</p><ul><li>JavaScript bundles are not excessively large.</li><li>Unused JavaScript is reduced where possible.</li><li>Main content is not delayed by heavy client-side rendering.</li><li>Largest Contentful Paint is not slowed by app shell rendering.</li><li>Interaction to Next Paint is not hurt by long JavaScript tasks.</li><li>Third-party scripts are not blocking important rendering.</li><li>Images are optimized and not dependent on late client-side loading.</li><li>Fonts do not cause major layout shifts.</li><li>Lazy loading does not hide important content from crawlers.</li><li>Core Web Vitals are reviewed for priority templates, not just the homepage.</li></ul><p>A SPA can feel fast to your team and still be slow for SEO. If your JavaScript takes too long to deliver the message, the page loses twice: once in search and once in conversion.</p><h2 id="10-ux-and-conversion-risks" class="portable-heading portable-heading-h2">10. UX and Conversion Risks</h2><p>A <strong>SPA SEO audit</strong> should not stop at indexability. If a page gets traffic but fails to convert, the business still loses.</p><p>Check:</p><ul><li>The main value proposition is visible without waiting for full app hydration.</li><li>Calls to action appear early and work reliably.</li><li>Forms do not break when JavaScript errors occur.</li><li>Pricing, demo, signup, or checkout paths are crawlable and usable.</li><li>Error states are clear and recoverable.</li><li>Page copy explains what the product or service does without relying on animations.</li><li>Navigation is understandable without app-specific behavior.</li><li>Mobile users can access the same core content.</li><li>Tracking scripts do not slow the page or interfere with rendering.</li><li>Conversion pages are not accidentally noindexed.</li></ul><p>The goal is not a green score. The goal is a page that can be found, understood, trusted, and acted on.</p><h2 id="11-framework-and-architecture-review" class="portable-heading portable-heading-h2">11. Framework and Architecture Review</h2><p>Different JavaScript setups create different SEO risks. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. But you need to know how each important page is being delivered.</p><p>Check:</p><ul><li>The rendering mode is known for each important template.</li><li>Server-side rendering, static generation, client-side rendering, or pre-rendering is documented.</li><li>Developers and SEO teams agree which pages must be indexable.</li><li>Public marketing pages are not treated like logged-in app screens.</li><li>Framework upgrades are tested for rendering changes.</li><li>Route-level metadata is tested after deployments.</li><li>Build changes do not accidentally remove pre-rendered content.</li><li>API failures do not produce thin indexable pages.</li><li>Error boundaries do not hide content from crawlers.</li><li>SEO checks are included before major releases.</li></ul><p>The exact fix depends on the stack. The audit pattern stays the same: <strong>prove what crawlers get, then fix the gap.</strong></p><h2 id="12-google-search-console-checks" class="portable-heading portable-heading-h2">12. Google Search Console Checks</h2><p>Google Search Console will not tell you everything, but it will show useful symptoms.</p><p>Check:</p><ul><li>Important URLs are indexed.</li><li>Important URLs are not stuck in “Discovered, currently not indexed” without explanation.</li><li>Important URLs are not excluded by <code>noindex</code>.</li><li>Google’s selected canonical matches your intended canonical.</li><li>Crawled pages show the expected content.</li><li>Page indexing reports are reviewed by template type.</li><li>Sitemap submissions match your indexable URL strategy.</li><li>Performance data is reviewed for pages that should drive revenue.</li><li>Query data is checked for technical GEO, AEO, and crawlability demand.</li><li>Drops are compared against deployments, migrations, and framework changes.</li></ul><p>Treat Search Console as evidence, not a magic oracle. If impressions are weak, pages are excluded, or Google chooses unexpected canonicals, your JavaScript delivery may be part of the problem.</p><h2 id="13-log-file-and-bot-behavior-review" class="portable-heading portable-heading-h2">13. Log File and Bot Behavior Review</h2><p>If you have log access, use it. Logs show what crawlers actually did.</p><p>Check:</p><ul><li>Googlebot is crawling important URLs.</li><li>Important sections are not being ignored.</li><li>Crawl frequency changed after a migration or release.</li><li>Bots are hitting redirected or broken routes too often.</li><li>Server responses for crawlers are clean and consistent.</li><li>Static assets needed for rendering are accessible.</li><li>Non-Google crawlers are not accidentally blocked if AI visibility matters.</li><li>Crawl waste is reduced on low-value routes.</li><li>Money pages receive crawl attention.</li><li>Bot behavior aligns with your sitemap and internal linking strategy.</li></ul><p>Logs are useful because they show reality: not what the crawler could do, not what the framework should do, but what actually happened.</p><h2 id="14-copy-and-content-extraction" class="portable-heading portable-heading-h2">14. Copy and Content Extraction</h2><p>JavaScript SEO is not only technical. Once crawlers reach the page, they still need meaningful content.</p><p>Check:</p><ul><li>The page clearly states what the company, product, or service does.</li><li>The target audience is obvious.</li><li>The problem, solution, and outcome are explained.</li><li>Important terms are written naturally in visible copy.</li><li>Headings describe the page, not just marketing slogans.</li><li>Feature descriptions are not hidden inside components that require JavaScript to populate.</li><li>FAQs answer real buyer or technical questions.</li><li>Comparison and alternative pages include enough context to be useful.</li><li>Thin pages are improved or removed from indexation.</li><li>AI extraction would produce an accurate summary of the page.</li></ul><p>Crawlability gets the page seen. Good copy gets the page understood. Clear conversion paths get the buyer moving. You need all three.</p><h2 id="15-ci-and-release-monitoring" class="portable-heading portable-heading-h2">15. CI and Release Monitoring</h2><p>A one-time audit helps. A repeatable process protects you from regressions.</p><p>Check:</p><ul><li>Priority URLs are tested before major releases.</li><li>Raw HTML snapshots are compared over time.</li><li>Rendered HTML snapshots are compared over time.</li><li>Metadata changes are monitored.</li><li>Canonical changes are monitored.</li><li>Robots directives are monitored.</li><li>Schema presence is tested.</li><li>Internal links are crawled after deployments.</li><li>Performance regressions are flagged.</li><li>SEO-critical templates have QA requirements.</li></ul><p>JavaScript SEO problems often appear after innocent changes: a route refactor, framework upgrade, hydration fix, analytics script, redesign, CMS change, or deployment config update. None of those sound like SEO projects. They can still break SEO.</p><h2 id="how-savage-audit-fits-naturally" class="portable-heading portable-heading-h2">How Savage Audit Fits Naturally</h2><p>Savage Audit is built for exactly this kind of problem.</p><p>JavaScript-heavy websites usually sit between three teams:</p><ul><li>Developers care about architecture, deployment, performance, and maintainability.</li><li>SEO teams care about crawlability, indexation, rankings, and structured data.</li><li>Founders and marketers care about pipeline, demos, signups, and revenue.</li></ul><p>Everyone can be right and the site can still be broken.</p><p>Savage Audit helps identify JavaScript crawlability problems, single page application SEO issues, raw HTML vs rendered HTML gaps, metadata and canonical failures, AI crawlability risks, technical SEO blockers, UX problems, copy gaps, and prioritized fixes your dev team can actually use.</p><p>For related technical checks, see the <!-- -->Technical GEO Audit Checklist<!-- -->, the <!-- -->Website Audit Tool for Developers<!-- -->, and the guide to <!-- -->LLMs.txt vs Robots.txt vs Structured Data<!-- -->.</p><p>The point is not to shame the stack. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. The point is to stop pretending the browser experience is the same as crawler access.</p><h2 id="final-takeaway" class="portable-heading portable-heading-h2">Final Takeaway</h2><p>Your single page application can look beautiful in the browser and still be a search liability.</p><p>Do not start with vanity metrics. Do not start by rewriting every headline. Do not assume “Google can render JavaScript” means your crawlability is fine.</p><p>Start with proof.</p><p>Compare raw HTML against rendered HTML. Check internal links. Verify metadata. Test schema. Review robots directives. Look at crawl access. Then check whether AI crawlers can extract the same core content your users see.</p><p>If bots cannot read your app, buyers may never find it. That is the real JavaScript SEO audit.</p></section><section class="blog-faqs" aria-labelledby="blog-faqs"><div class="blog-faqs-copy"><span class="badge">FAQ</span><h2 id="blog-faqs">Common questions</h2></div><div class="blog-faq-list"><article class="blog-faq-item"><h3>What is a JavaScript SEO audit?</h3><p>A JavaScript SEO audit checks whether a JavaScript-heavy website can be discovered, rendered, indexed, understood, and ranked by search engines. It compares raw HTML, rendered HTML, metadata, internal links, schema, status codes, performance, and crawl access.</p></article><article class="blog-faq-item"><h3>What is an AI crawlability audit checklist?</h3><p>An AI crawlability audit checklist verifies whether AI crawlers and answer engines can extract useful content from your site. It focuses on raw HTML access, clear copy, structured data, crawl permissions, internal links, and whether important content requires complex JavaScript execution.</p></article><article class="blog-faq-item"><h3>How do I check Backbone.js crawlability?</h3><p>For Backbone.js crawlability, start with routing and raw HTML. Check whether important URLs return meaningful content on direct server requests, whether internal links use crawlable anchors, and whether metadata is available before client-side DOM manipulation.</p></article><article class="blog-faq-item"><h3>When should I run a SPA SEO audit?</h3><p>Run a SPA SEO audit before launches, migrations, redesigns, framework upgrades, and major routing changes. Also run one after unexplained organic traffic drops, indexation problems, canonical issues, or performance regressions.</p></article><article class="blog-faq-item"><h3>Why is my SPA indexed but not ranking well?</h3><p>An SPA can be indexed but still rank poorly if crawlers see thin raw HTML, delayed content, weak internal links, slow rendering, inconsistent metadata, or confusing canonicals. Indexing does not prove search engines fully understood the page.</p></article></div></section><section class="blog-curated-links" aria-labelledby="curated-related-links"><div class="blog-section-heading"><span class="badge">Next audit steps</span><h2 id="curated-related-links">Keep the diagnosis moving</h2></div><div class="blog-related-grid"><a class="blog-related-card blog-related-card--curated" title="Technical GEO Audit Checklist" href="/blog/technical-geo-audit-checklist"><span class="mono">SavageAudit path</span><strong>Technical GEO Audit Checklist</strong><small>Check crawlability, structured data, entity clarity, and citation readiness for AI search.</small></a><a class="blog-related-card blog-related-card--curated" title="Website Audit Tool for Developers" href="/blog/website-audit-tool-for-developers"><span class="mono">SavageAudit path</span><strong>Website Audit Tool for Developers</strong><small>Review technical SEO, UX, copy, trust, conversion, and AI visibility before launch.</small></a><a class="blog-related-card blog-related-card--curated" title="LLMs.txt vs Robots.txt vs Structured Data" href="/blog/llms-txt-vs-robots-txt-vs-structured-data"><span class="mono">SavageAudit path</span><strong>LLMs.txt vs Robots.txt vs Structured Data</strong><small>Understand which technical signals actually help AI discovery.</small></a></div></section><section class="blog-related-reads" aria-labelledby="related-reads"><div class="blog-section-heading"><span class="badge">Related reads</span><h2 id="related-reads">Keep auditing the outside view</h2></div><div class="blog-related-grid"><a class="blog-related-card" title="Website Audit Tool for Developers: What to Check Before You Ship" href="/blog/website-audit-tool-for-developers"><span class="mono">Technical Teardowns</span><strong>Website Audit Tool for Developers: What to Check Before You Ship</strong><small>13<!-- --> min read<!-- --> by SavageAudit Team</small></a><a class="blog-related-card" title="Technical GEO Audit Checklist: Crawlability, Structured Data, and AI Citation Readiness" href="/blog/technical-geo-audit-checklist"><span class="mono">Technical Teardowns</span><strong>Technical GEO Audit Checklist: Crawlability, Structured Data, and AI Citation Readiness</strong><small>13<!-- --> min read<!-- --> by SavageAudit Team</small></a><a class="blog-related-card" title="Speed, UX, and SEO Audit Tool: How to Review All Three Together" href="/blog/website-speed-ux-seo-audit-tool"><span class="mono">Product Updates</span><strong>Speed, UX, and SEO Audit Tool: How to Review All Three Together</strong><small>12<!-- --> min read<!-- --> by SavageAudit Team</small></a><a class="blog-related-card blog-related-card--static" title="Browse all SavageAudit articles" href="/blog"><span class="mono">More research</span><strong>Browse the full SavageAudit blog</strong><small>SEO, AI visibility, UX, proof, and conversion teardown notes.</small></a></div></section><section class="blog-article-cta" aria-labelledby="article-cta"><div><span class="badge">SavageAudit</span><h2 id="article-cta">Run your own public presence audit</h2><p>See how your website, search footprint, AI visibility, social proof, and conversion trust look from the outside.</p></div><div class="blog-article-cta-actions"><a class="primary" title="Roast My Site" href="/#home-roast-input">Roast My Site</a><a class="secondary" title="View pricing" href="/pricing">View pricing</a><a class="secondary" title="Compare websites" href="/compare">Compare sites</a></div></section><footer class="blog-article-footer"><a class="mono blog-back-link" title="Go to SavageAudit blog" href="/blog">Back to blog</a><div class="blog-share-buttons" aria-label="Share this article"><a aria-label="Share on X" class="blog-share-button" href="https://twitter.com/intent/tweet?text=JavaScript%20SEO%20Audit%20Checklist%20for%20SPAs%3A%20Make%20Sure%20Crawlers%20Can%20Actually%20Read%20Your%20Site&url=https%3A%2F%2Fsavageaudit.com%2Fblog%2Fjavascript-seo-audit-checklist-single-page-apps" rel="noreferrer" target="_blank" title="Share on X">X</a><a aria-label="Share on LinkedIn" class="blog-share-button" href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fsavageaudit.com%2Fblog%2Fjavascript-seo-audit-checklist-single-page-apps" rel="noreferrer" target="_blank" title="Share on LinkedIn">in<span class="sr-only">Share on LinkedIn</span></a><button aria-label="Copy article link" class="blog-share-button" title="Copy article link" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><span class="sr-only">Copy article link</span></button></div></footer></div></div></article></main><!--$--><!--/$--><!--/&--><!--/&--><!--/&--><!--$?--><template id="B:2"></template><!--/$--><script>requestAnimationFrame(function(){$RT=performance.now()});</script><script src="/_next/static/chunks/d595fbba81e686e7.js" id="_R_" async=""></script><div hidden id="S:2"><footer class="site-footer"><div class="site-footer-inner"><div class="site-footer-shell"><div class="site-footer-glow" aria-hidden="true"></div><div class="site-footer-glow site-footer-glow--cool" aria-hidden="true"></div><div class="site-footer-grid" aria-hidden="true"></div><div class="site-footer-topline" aria-hidden="true"></div><div class="site-footer-hero"><div class="site-footer-brand-column"><a class="site-footer-brand" title="Go to SavageAudit home" href="/"><span class="site-footer-logo-wrap"><img alt="SavageAudit" title="SavageAudit" loading="lazy" width="34" height="34" decoding="async" data-nimg="1" class="site-footer-logo" style="color:transparent" srcSet="/_next/image?url=%2Flogo.png&w=48&q=75 1x, /_next/image?url=%2Flogo.png&w=96&q=75 2x" src="/_next/image?url=%2Flogo.png&w=96&q=75"/><span class="site-footer-logo-ring" aria-hidden="true"></span></span><span class="site-footer-brand-copy"><span class="mono site-footer-brand-kicker">SavageAudit<!-- --> · Live</span><span class="site-footer-brand-title">The AI Audit Your Developer Fears</span></span></a><div class="site-footer-wordmark-block"><div class="site-footer-wordmark" aria-hidden="true" data-text="SavageAudit"><span class="site-footer-wordmark-part site-footer-wordmark-part--savage">Savage</span><span class="site-footer-wordmark-part site-footer-wordmark-part--audit">Audit</span></div></div><p class="site-footer-headline">Brutal audits. Clear fixes.</p></div><aside class="site-footer-panel"><span class="mono site-footer-panel-kicker">SavageAudit<!-- --> Proof</span><p class="site-footer-panel-title">Find leaks. Ship fixes.</p><p>Evidence across SEO, UX, copy, speed, and conversion.</p><div class="site-footer-proof-list"><a class="site-footer-proof-row" title="Go to AI Visibility Audit" href="/ai-visibility-audit"><span class="mono site-footer-proof-index">01</span><span>AI Visibility Audit</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a><a class="site-footer-proof-row" title="Go to Online Presence Audit" href="/internet-social-presence-audit"><span class="mono site-footer-proof-index">02</span><span>Online Presence Audit</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a><a class="site-footer-proof-row" title="Go to SEO + GEO Audit Tool" href="/seo-geo-audit-tool"><span class="mono site-footer-proof-index">03</span><span>SEO + GEO Audit Tool</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a><a class="site-footer-proof-row" title="Go to Google Search Console Audit Dashboard" href="/google-search-console-audit-dashboard"><span class="mono site-footer-proof-index">04</span><span>Google Search Console Audit Dashboard</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a><a class="site-footer-proof-row" title="Go to AI Growth Action Plan" href="/ai-growth-action-plan"><span class="mono site-footer-proof-index">05</span><span>AI Growth Action Plan</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a><a class="site-footer-proof-row" title="Go to SavageAudit vs Traditional SEO Audit Tools" href="/savageaudit-vs-traditional-seo-audit-tools"><span class="mono site-footer-proof-index">06</span><span>SavageAudit vs Traditional SEO Audit Tools</span><span class="site-footer-proof-arrow" aria-hidden="true">↗</span></a></div></aside></div><div class="site-footer-links-grid"><div class="site-footer-link-block"><span class="mono site-footer-link-title">Platform</span><div class="site-footer-link-list"><a class="site-footer-link" title="Go to Roast My Site" href="/"><span>Roast My Site</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Gallery" href="/gallery"><span>Gallery</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Leaderboard" href="/leaderboard"><span>Leaderboard</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Pricing" href="/pricing"><span>Pricing</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a></div></div><div class="site-footer-link-block"><span class="mono site-footer-link-title">Explore</span><div class="site-footer-link-list"><a class="site-footer-link" title="Go to Compare" href="/compare"><span>Compare</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Blog" href="/blog"><span>Blog</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Create Free Account" href="/sign-in?tab=signup"><span>Create Free Account</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Sign In" href="/sign-in"><span>Sign In</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a></div></div><div class="site-footer-link-block"><span class="mono site-footer-link-title">Our Ventures</span><div class="site-footer-link-list"><a href="https://zutilo.com" class="site-footer-link" title="Open zutilo.com (external link)" target="_blank" rel="noopener noreferrer follow"><span>zutilo.com</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a href="https://allblogs.in" class="site-footer-link" title="Open allblogs.in (external link)" target="_blank" rel="noopener noreferrer follow"><span>allblogs.in</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a href="https://hevyanexus.com" class="site-footer-link" title="Open hevyanexus.com (external link)" target="_blank" rel="noopener noreferrer follow"><span>hevyanexus.com</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a></div></div><div class="site-footer-link-block"><span class="mono site-footer-link-title">Legal</span><div class="site-footer-link-list"><a class="site-footer-link" title="Go to Privacy" href="/privacy"><span>Privacy</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Terms" href="/terms"><span>Terms</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Cookies" href="/cookies"><span>Cookies</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Contact" href="/contact"><span>Contact</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a></div></div><div class="site-footer-link-block"><span class="mono site-footer-link-title">Audit Proof</span><div class="site-footer-link-list"><a class="site-footer-link" title="Go to Full Website Audit" href="/full-site-audit"><span>Full Website Audit</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Compare Websites" href="/compare-websites"><span>Compare Websites</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Website Audit Checklist" href="/website-audit-categories"><span>Website Audit Checklist</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a><a class="site-footer-link" title="Go to Content Audit Tool for SaaS" href="/content-audit-tool-for-saas"><span>Content Audit Tool for SaaS</span><span class="site-footer-link-arrow" aria-hidden="true">↗</span></a></div></div></div><div class="site-footer-bottom"><p class="mono site-footer-meta">© <!-- -->2026<!-- --> <!-- -->SavageAudit<!-- --> · All systems roasting.</p><div class="site-footer-socials"><a href="https://x.com/savageaudit" title="Open X profile" class="site-footer-social" aria-label="X" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" aria-hidden="true" focusable="false"><path d="M18.901 1.153h3.681l-8.041 9.188L24 22.847h-7.406l-5.8-7.584-6.64 7.584H.47l8.6-9.83L0 1.154h7.594l5.243 6.932zM17.61 20.645h2.04L6.486 3.24H4.298z"></path></svg></span><span class="site-footer-social-label">X</span></a><a href="https://www.threads.com/@savageaudit" title="Open Threads profile" class="site-footer-social" aria-label="Threads" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" aria-hidden="true" focusable="false"><path d="M16.3 10.17c-.1-.05-.2-.09-.3-.14-.2-1.56-1.08-2.45-2.2-2.98-.8-.39-1.72-.52-2.76-.52-2.56 0-4.37 1.54-4.37 3.88 0 1.96 1.35 3.31 3.41 3.31 1.4 0 2.29-.65 2.84-1.56l-1.31-.74c-.24.47-.69.99-1.48.99-.94 0-1.58-.67-1.58-1.69 0-1.39 1.08-2.22 2.49-2.22 1.44 0 2.31.65 2.58 1.97-.74-.14-1.56-.19-2.41-.09-1.88.22-3.06 1.28-3.06 2.88 0 1.62 1.33 2.73 3.17 2.73 1.49 0 2.66-.56 3.37-1.57.63-.9.88-2.07.74-3.54.45.26.79.67.99 1.21.46 1.23.31 3.03-.81 4.51-1.12 1.47-3.14 2.34-5.52 2.34-2.31 0-4.31-.79-5.64-2.21C4.4 18.25 3.7 16.22 3.7 14c0-2.32.74-4.35 2.09-5.71 1.35-1.36 3.27-2.08 5.58-2.08 2.29 0 4.18.7 5.45 2.03 1.03 1.08 1.69 2.49 1.95 4.21l1.54-.23c-.3-2-1.08-3.68-2.37-5.02-1.58-1.66-3.85-2.53-6.57-2.53-2.76 0-5.08.87-6.72 2.52C3 8.85 2.13 11.16 2.13 14c0 2.63.83 5.05 2.33 6.8 1.63 1.89 4.01 2.89 6.89 2.89 2.92 0 5.39-1.08 6.95-3.04 1.55-1.95 1.77-4.42 1.06-6.29-.43-1.12-1.19-1.93-2.24-2.46Zm-4.88 5.11c-.95 0-1.57-.43-1.57-1.08 0-.55.43-1.21 1.82-1.38.66-.08 1.34-.04 1.94.08-.11 1.63-.95 2.38-2.19 2.38Z"></path></svg></span><span class="site-footer-social-label">Threads</span></a><a href="https://www.instagram.com/savageaudit" title="Open Instagram profile" class="site-footer-social" aria-label="Instagram" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><rect x="3" y="3" width="18" height="18" rx="5"></rect><circle cx="12" cy="12" r="4.2"></circle><circle cx="17.4" cy="6.6" r="1.1" fill="currentColor" stroke="none"></circle></svg></span><span class="site-footer-social-label">Instagram</span></a><a href="https://www.youtube.com/@savageaudit" title="Open YouTube profile" class="site-footer-social" aria-label="YouTube" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" aria-hidden="true" focusable="false"><path d="M21.58 7.19a2.98 2.98 0 0 0-2.1-2.11C17.63 4.5 12 4.5 12 4.5s-5.63 0-7.48.58a2.98 2.98 0 0 0-2.1 2.11A31.2 31.2 0 0 0 1.83 12c0 1.62.2 3.22.59 4.81a2.98 2.98 0 0 0 2.1 2.11c1.85.58 7.48.58 7.48.58s5.63 0 7.48-.58a2.98 2.98 0 0 0 2.1-2.11c.39-1.59.59-3.19.59-4.81 0-1.62-.2-3.22-.59-4.81ZM10.2 15.04V8.96L15.4 12l-5.2 3.04Z"></path></svg></span><span class="site-footer-social-label">YouTube</span></a><a href="https://www.linkedin.com/company/savageaudit" title="Open LinkedIn profile" class="site-footer-social" aria-label="LinkedIn" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" aria-hidden="true" focusable="false"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.024-3.037-1.849-3.037-1.851 0-2.134 1.445-2.134 2.939v5.667H9.356V9h3.414v1.561h.049c.476-.9 1.637-1.849 3.37-1.849 3.601 0 4.266 2.369 4.266 5.455zM5.337 7.433a2.063 2.063 0 1 1 0-4.126 2.063 2.063 0 0 1 0 4.126M7.119 20.452H3.554V9h3.565z"></path></svg></span><span class="site-footer-social-label">LinkedIn</span></a><a href="https://github.com/savageaudit" title="Open GitHub profile" class="site-footer-social" aria-label="GitHub" target="_blank" rel="noreferrer"><span class="mono site-footer-social-badge"><svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" aria-hidden="true" focusable="false"><path d="M12 .296a12 12 0 0 0-3.792 23.39c.6.11.82-.26.82-.577v-2.18c-3.338.726-4.042-1.417-4.042-1.417-.546-1.387-1.333-1.757-1.333-1.757-1.09-.746.082-.731.082-.731 1.205.084 1.838 1.236 1.838 1.236 1.07 1.834 2.807 1.304 3.492.997.108-.775.418-1.304.762-1.603-2.665-.304-5.467-1.332-5.467-5.93 0-1.31.468-2.38 1.235-3.22-.124-.304-.536-1.527.117-3.176 0 0 1.007-.322 3.3 1.23a11.46 11.46 0 0 1 6.006 0c2.292-1.552 3.298-1.23 3.298-1.23.654 1.649.242 2.872.12 3.176.768.84 1.233 1.91 1.233 3.22 0 4.61-2.807 5.624-5.48 5.921.43.37.823 1.102.823 2.222v3.293c0 .32.216.694.825.576A12 12 0 0 0 12 .296"></path></svg></span><span class="site-footer-social-label">GitHub</span></a></div></div></div></div></footer></div><script>$RB=[];$RV=function(a){$RT=performance.now();for(var b=0;b<a.length;b+=2){var c=a[b],e=a[b+1];null!==e.parentNode&&e.parentNode.removeChild(e);var f=c.parentNode;if(f){var g=c.previousSibling,h=0;do{if(c&&8===c.nodeType){var d=c.data;if("/$"===d||"/&"===d)if(0===h)break;else h--;else"$"!==d&&"$?"!==d&&"$~"!==d&&"$!"!==d&&"&"!==d||h++}d=c.nextSibling;f.removeChild(c);c=d}while(c);for(;e.firstChild;)f.insertBefore(e.firstChild,c);g.data="$";g._reactRetry&&requestAnimationFrame(g._reactRetry)}}a.length=0}; $RC=function(a,b){if(b=document.getElementById(b))(a=document.getElementById(a))?(a.previousSibling.data="$~",$RB.push(a,b),2===$RB.length&&("number"!==typeof $RT?requestAnimationFrame($RV.bind(null,$RB)):(a=performance.now(),setTimeout($RV.bind(null,$RB),2300>a&&2E3<a?2300-a:$RT+300-a)))):b.parentNode.removeChild(b)};$RC("B:2","S:2")</script><script>$RX=function(b,c,d,e,f){var a=document.getElementById(b);a&&(b=a.previousSibling,b.data="$!",a=a.dataset,c&&(a.dgst=c),d&&(a.msg=d),e&&(a.stck=e),f&&(a.cstck=f),b._reactRetry&&b._reactRetry())};;$RX("B:0","BAILOUT_TO_CLIENT_SIDE_RENDERING")</script><script>$RX("B:1","BAILOUT_TO_CLIENT_SIDE_RENDERING")</script></body></html><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[79033,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\"],\"\"]\n3:\"$Sreact.suspense\"\n4:I[73557,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\",\"/_next/static/chunks/4a5f7fe3618af5fa.js\"],\"\"]\n5:I[30076,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\",\"/_next/static/chunks/4a5f7fe3618af5fa.js\"],\"Image\"]\n10:I[35015,[],\"default\"]\n11:I[63833,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\"],\"default\"]\n12:I[45081,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\"],\"ProductEventRouteTracker\"]\n13:I[96511,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"default\"]\n14:I[90515,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"default\"]\n15:I[42300,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\"],\"default\"]\n17:I[92222,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"OutletBoundary\"]\n19:I[92222,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"ViewportBoundary\"]\n1b:I[92222,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"MetadataBoundary\"]\n20:I[29539,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\",\"/_next/static/chunks/4a5f7fe3618af5fa.js\"],\"BlogShareButtons\"]\n22:I[84404,[\"/_next/static/chunks/2fec94da2da5e072.js\",\"/_next/static/chunks/438b64bba92d9518.js\",\"/_next/static/chunks/4f8d7e3a3122a819.js\",\"/_next/static/chunks/4a5f7fe3618af5fa.js\"],\"ArticleProgressClient\"]\na8:I[73972,[\"/_next/static/chunks/f5a892271306ea97.js\",\"/_next/static/chunks/54fb72e67460ec66.js\"],\"IconMark\"]\n:HL[\"/_next/static/chunks/5a2c19a6816fbd29.css\",\"style\"]\n:HL[\"/_next/static/chunks/9cc23f674d3f7fc2.css\",\"style\"]\n:HL[\"/_next/static/media/0c89a48fa5027cee-s.p.4564287c.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/70bc3e132a0a741e-s.p.15008bfb.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/fabcf92ba1ccea36-s.p.19f28380.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"DwNPJ28Z6Fg4IbYHdn4am\",\"c\":[\"\",\"blog\",\"javascript-seo-audit-checklist-single-page-apps\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"blog\",{\"children\":[[\"slug\",\"javascript-seo-audit-checklist-single-page-apps\",\"d\"],{\"children\":[\"__PAGE__\",{}]}]}]},\"$undefined\",\"$undefined\",true],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/5a2c19a6816fbd29.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"link\",\"1\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/9cc23f674d3f7fc2.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/2fec94da2da5e072.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/438b64bba92d9518.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-2\",{\"src\":\"/_next/static/chunks/4f8d7e3a3122a819.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"data-scroll-behavior\":\"smooth\",\"children\":[\"$\",\"body\",null,{\"className\":\"bebas_neue_3fba93a6-module__flghoW__variable space_grotesk_d70bcd2d-module__Q5MVZa__variable jetbrains_mono_713998fa-module__BrHHUG__variable\",\"children\":[[[\"$\",\"$L2\",null,{\"src\":\"https://www.googletagmanager.com/gtag/js?id=G-3WTBBJ4N9F\",\"strategy\":\"afterInteractive\"}],[\"$\",\"$L2\",null,{\"id\":\"google-analytics\",\"strategy\":\"afterInteractive\",\"children\":\"\\n window.dataLayer = window.dataLayer || [];\\n function gtag(){dataLayer.push(arguments);}\\n gtag(\\\"js\\\", new Date());\\n gtag(\\\"config\\\", \\\"G-3WTBBJ4N9F\\\");\\n \"}]],[\"$\",\"script\",null,{\"type\":\"application/ld+json\",\"dangerouslySetInnerHTML\":{\"__html\":\"{\\\"@context\\\":\\\"https://schema.org\\\",\\\"@type\\\":\\\"Organization\\\",\\\"@id\\\":\\\"https://savageaudit.com/#organization\\\",\\\"name\\\":\\\"SavageAudit\\\",\\\"alternateName\\\":[\\\"Savage Audit\\\",\\\"AI website audit tool\\\",\\\"Website audit tool\\\",\\\"AI visibility audit tool\\\",\\\"SEO audit tool\\\"],\\\"url\\\":\\\"https://savageaudit.com\\\",\\\"email\\\":\\\"info@savageaudit.com\\\",\\\"logo\\\":\\\"https://savageaudit.com/logo.png\\\",\\\"sameAs\\\":[\\\"https://x.com/savageaudit\\\",\\\"https://www.linkedin.com/company/savageaudit\\\",\\\"https://www.youtube.com/@savageaudit\\\",\\\"https://github.com/savageaudit\\\"]}\"}}],[\"$\",\"script\",null,{\"type\":\"application/ld+json\",\"dangerouslySetInnerHTML\":{\"__html\":\"{\\\"@context\\\":\\\"https://schema.org\\\",\\\"@type\\\":\\\"WebSite\\\",\\\"@id\\\":\\\"https://savageaudit.com/#website\\\",\\\"name\\\":\\\"SavageAudit\\\",\\\"alternateName\\\":[\\\"AI Website Audit Tool\\\",\\\"Website Audit Tool\\\",\\\"Automated Website Auditor\\\",\\\"AI Visibility Audit Tool\\\",\\\"SEO Audit Tool\\\"],\\\"url\\\":\\\"https://savageaudit.com\\\",\\\"description\\\":\\\"The AI Audit Your Developer Fears\\\",\\\"publisher\\\":{\\\"@id\\\":\\\"https://savageaudit.com/#organization\\\"}}\"}}],[\"$\",\"$3\",null,{\"fallback\":[\"$\",\"nav\",null,{\"className\":\"navbar navbar-scrolled\",\"children\":[[\"$\",\"div\",null,{\"className\":\"navbar-glow-line\",\"aria-hidden\":\"true\"}],[\"$\",\"div\",null,{\"className\":\"navbar-inner\",\"children\":[[\"$\",\"$L4\",null,{\"href\":\"/\",\"className\":\"navbar-brand\",\"title\":\"Go to SavageAudit home\",\"children\":[[\"$\",\"div\",null,{\"className\":\"navbar-logo-wrap\",\"children\":[[\"$\",\"$L5\",null,{\"src\":\"/logo.png\",\"alt\":\"SavageAudit\",\"title\":\"SavageAudit\",\"width\":28,\"height\":28,\"className\":\"navbar-logo\",\"unoptimized\":true}],[\"$\",\"div\",null,{\"className\":\"navbar-logo-pulse\"}]]}],[\"$\",\"span\",null,{\"className\":\"navbar-wordmark\",\"children\":[\"Savage\",[\"$\",\"span\",null,{\"className\":\"navbar-wordmark-accent\",\"children\":\"Audit\"}]]}]]}],[\"$\",\"div\",null,{\"className\":\"navbar-links\",\"children\":[\"$\",\"div\",null,{\"className\":\"navbar-pill-group\",\"children\":[[\"$\",\"$L4\",\"/gallery\",{\"href\":\"/gallery\",\"title\":\"Go to Gallery\",\"className\":\"navbar-pill\",\"children\":[[\"$\",\"span\",null,{\"className\":\"navbar-pill-icon\",\"children\":\"◆\"}],\"Gallery\"]}],[\"$\",\"$L4\",\"/leaderboard\",{\"href\":\"/leaderboard\",\"title\":\"Go to Leaderboard\",\"className\":\"navbar-pill\",\"children\":[[\"$\",\"span\",null,{\"className\":\"navbar-pill-icon\",\"children\":\"◈\"}],\"Leaderboard\"]}],[\"$\",\"$L4\",\"/compare\",{\"href\":\"/compare\",\"title\":\"Go to Compare\",\"className\":\"navbar-pill\",\"children\":[[\"$\",\"span\",null,{\"className\":\"navbar-pill-icon\",\"children\":\"⇄\"}],\"Compare\"]}],[\"$\",\"$L4\",\"/pricing\",{\"href\":\"/pricing\",\"title\":\"Go to Pricing\",\"className\":\"navbar-pill\",\"children\":[\"$L6\",\"Pricing\"]}]]}]}],\"$L7\"]}]]}],\"children\":\"$L8\"}],\"$L9\",\"$La\",\"$Lb\"]}]}]]}],{\"children\":[\"$Lc\",{\"children\":[\"$Ld\",{\"children\":[\"$Le\",{},null,true,false]},null,true,false]},null,true,false]},null,true,false],\"$Lf\",true]],\"m\":\"$undefined\",\"G\":[\"$10\",[]],\"S\":true}\n"])</script><script>self.__next_f.push([1,"6:[\"$\",\"span\",null,{\"className\":\"navbar-pill-icon\",\"children\":\"⬡\"}]\n7:[\"$\",\"div\",null,{\"className\":\"navbar-actions\",\"children\":[[\"$\",\"div\",null,{\"className\":\"navbar-desktop-auth\",\"children\":[\"$\",\"span\",null,{\"className\":\"navbar-auth-placeholder\",\"aria-hidden\":\"true\",\"children\":[[\"$\",\"span\",null,{\"className\":\"navbar-auth-placeholder-dot\"}],[\"$\",\"span\",null,{\"className\":\"navbar-auth-placeholder-line\"}]]}]}],[\"$\",\"$L4\",null,{\"href\":\"/#home-roast-input\",\"className\":\"navbar-cta\",\"title\":\"Audit My Site\",\"children\":[[\"$\",\"span\",null,{\"className\":\"navbar-cta-glow\"}],\"Audit My Site\",[\"$\",\"svg\",null,{\"width\":\"14\",\"height\":\"14\",\"viewBox\":\"0 0 24 24\",\"fill\":\"none\",\"stroke\":\"currentColor\",\"strokeWidth\":\"2.5\",\"strokeLinecap\":\"round\",\"strokeLinejoin\":\"round\",\"children\":[[\"$\",\"polyline\",null,{\"points\":\"13 17 18 12 13 7\"}],[\"$\",\"polyline\",null,{\"points\":\"6 17 11 12 6 7\"}]]}]]}]]}]\n8:[\"$\",\"$L11\",null,{}]\n9:[\"$\",\"$3\",null,{\"fallback\":null,\"children\":[\"$\",\"$L12\",null,{}]}]\na:[\"$\",\"$L13\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L14\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"main\",null,{\"children\":[[\"$\",\"div\",null,{\"className\":\"flame-field\",\"aria-hidden\":\"true\",\"children\":[[\"$\",\"span\",null,{}],[\"$\",\"span\",null,{}],[\"$\",\"span\",null,{}]]}],[\"$\",\"div\",null,{\"className\":\"not-found\",\"children\":[[\"$\",\"h1\",null,{\"children\":\"404\"}],[\"$\",\"h2\",null,{\"children\":\"This URL is as broken as your mobile layout.\"}],[\"$\",\"p\",null,{\"className\":\"mono\",\"children\":\"We looked everywhere. Even checked your sitemap. You don't have one of those either.\"}],[\"$\",\"$L4\",null,{\"className\":\"primary\",\"href\":\"/\",\"title\":\"Go to SavageAudit home\",\"children\":\"Back to Roasting\"}]]}]]}],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]\nb:[\"$\",\"$3\",null,{\"fallback\":null,\"children\":[\"$\",\"$L15\",null,{}]}]\nc:[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L13\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L14\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]\nd:[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L13\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L14\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]\ne:[\"$\",\"$1\",\"c\",{\"children\":[\"$L16\",[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/4a5f7fe3618af5fa.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L17\",null,{\"children\":[\"$\",\"$3\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@18\"}]}]]}]\nf:[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L19\",null,{\"children\":\"$L1a\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L1b\",null,{\"children\":[\"$\",\"$3\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L1c\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}]\n1d:T71e0,"])</script><script>self.__next_f.push([1,"[{\"@context\":\"https://schema.org\",\"@type\":\"WebPage\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#webpage\",\"url\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\",\"name\":\"JavaScript SEO Audit Checklist for SPAs\",\"description\":\"Audit SPA crawlability, rendering, metadata, AI visibility, UX, and conversion risks before your JavaScript site loses search visibility.\",\"isPartOf\":{\"@type\":\"WebSite\",\"@id\":\"https://savageaudit.com/#website\"},\"publisher\":{\"@id\":\"https://savageaudit.com/#organization\"},\"mainEntity\":{\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#blogposting\"},\"breadcrumb\":{\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#breadcrumb\"},\"datePublished\":\"2026-07-17T12:00:00Z\",\"dateModified\":\"2026-07-17T12:00:00Z\",\"inLanguage\":\"en-US\",\"primaryImageOfPage\":{\"@type\":\"ImageObject\",\"url\":\"https://cdn.sanity.io/images/elyr32gq/production/46535ddf9afe2e9a2b8161a0d870b2ace3418e0b-1376x768.jpg?rect=0,23,1376,722\u0026w=1200\u0026h=630\u0026fit=crop\u0026auto=format\",\"width\":1200,\"height\":630},\"about\":[{\"@type\":\"Thing\",\"name\":\"Technical Teardowns\"},{\"@type\":\"Thing\",\"name\":\"Technical SEO \u0026 Website Audits\"}],\"hasPart\":[{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#short-answer-what-are-you-auditing\",\"name\":\"Short Answer: What Are You Auditing?\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#who-this-is-for\",\"name\":\"Who This Is For\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#what-to-check-first\",\"name\":\"What to Check First\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#1-discovery-and-internal-linking\",\"name\":\"1. Discovery and Internal Linking\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#2-raw-html-vs-rendered-html\",\"name\":\"2. Raw HTML vs Rendered HTML\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#3-rendering-and-hydration-risks\",\"name\":\"3. Rendering and Hydration Risks\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#4-metadata-and-robots-directives\",\"name\":\"4. Metadata and Robots Directives\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#5-canonicals-and-duplicate-url-control\",\"name\":\"5. Canonicals and Duplicate URL Control\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#6-structured-data-and-entity-clarity\",\"name\":\"6. Structured Data and Entity Clarity\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#7-ai-crawlability-aeo-and-geo\",\"name\":\"7. AI Crawlability, AEO, and GEO\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#8-robots-txt-status-codes-and-crawl-access\",\"name\":\"8. robots.txt, Status Codes, and Crawl Access\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#9-core-web-vitals-and-performance\",\"name\":\"9. Core Web Vitals and Performance\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#10-ux-and-conversion-risks\",\"name\":\"10. UX and Conversion Risks\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#11-framework-and-architecture-review\",\"name\":\"11. Framework and Architecture Review\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#12-google-search-console-checks\",\"name\":\"12. Google Search Console Checks\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#13-log-file-and-bot-behavior-review\",\"name\":\"13. Log File and Bot Behavior Review\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#14-copy-and-content-extraction\",\"name\":\"14. Copy and Content Extraction\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#15-ci-and-release-monitoring\",\"name\":\"15. CI and Release Monitoring\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#how-savage-audit-fits-naturally\",\"name\":\"How Savage Audit Fits Naturally\"},{\"@type\":\"WebPageElement\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#final-takeaway\",\"name\":\"Final Takeaway\"}]},{\"@context\":\"https://schema.org\",\"@type\":\"BlogPosting\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#blogposting\",\"headline\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\",\"name\":\"JavaScript SEO Audit Checklist for SPAs\",\"description\":\"Audit SPA crawlability, rendering, metadata, AI visibility, UX, and conversion risks before your JavaScript site loses search visibility.\",\"url\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\",\"datePublished\":\"2026-07-17T12:00:00Z\",\"dateModified\":\"2026-07-17T12:00:00Z\",\"inLanguage\":\"en-US\",\"image\":\"https://cdn.sanity.io/images/elyr32gq/production/46535ddf9afe2e9a2b8161a0d870b2ace3418e0b-1376x768.jpg?rect=0,23,1376,722\u0026w=1200\u0026h=630\u0026fit=crop\u0026auto=format\",\"articleBody\":\"A JavaScript SEO audit is a reality check.\\nIt answers one simple question: can search engines, AI crawlers, and real users all access the same important content on your JavaScript-heavy website?\\nYour site can look perfect in a browser and still be hard for crawlers to discover, render, understand, or trust. If your key content, internal links, metadata, and schema only appear after client-side JavaScript runs, you may not have a content problem. You may have a delivery problem.\\nBefore you blame rankings, rewrite every headline, or assume the algorithm hates you, check whether crawlers can actually see what you’re trying to rank.\\nShort Answer: What Are You Auditing?\\nA proper JavaScript SEO audit compares what a user sees in the browser with what crawlers can access before and after JavaScript rendering.\\nYou’re looking for five types of problems:\\nDiscovery gaps: crawlers can’t find your important URLs.\\nRendering gaps: raw HTML is empty, thin, or missing key content.\\nMetadata issues: titles, canonicals, robots tags, or schema show up too late or get overwritten.\\nAI crawlability risks: AI crawlers may not execute your JavaScript before extracting content.\\nUX and conversion drag: large bundles, slow rendering, hydration issues, and front-end bugs hurt users too.\\nThe blunt version: if your single page app makes the browser do all the work, prove bots can still understand the page. Don’t assume it.\\nWho This Is For\\nThis guide is for teams running JavaScript-heavy websites where organic visibility matters.\\nThat includes:\\nDevelopers and engineering leads working with React, Vue, Angular, Next.js, Nuxt, Backbone.js, or custom JavaScript apps.\\nTechnical founders who shipped a polished product but can’t figure out why organic traffic, demo requests, or signups are flat.\\nSEO teams responsible for SPA SEO, technical SEO crawlability, AEO, GEO, and AI visibility.\\nGrowth and marketing teams who suspect the content isn’t the real issue.\\nAgencies and consultants auditing modern websites where “view source” and “inspect element” tell two very different stories.\\nThis is not a meta description tune-up. This is a delivery audit.\\nWhat to Check First\\nPick one important page from your SPA or JavaScript-heavy site. Not a random page. Choose a page that should bring in qualified traffic, such as a product page, service page, pricing page, comparison page, location page, blog post, or use case page.\\nNow compare three versions of that page:\\nWhat a normal user sees in Chrome\\nWhat appears in the raw HTML source\\nWhat appears after a rendered crawl or headless browser render\\nYou’re looking for the gap between them.\\nIf Chrome shows a full, useful page but the raw HTML looks like this:\\n\u003cdiv id=\\\"root\\\"\u003e\u003c/div\u003e\\n\u003cscript src=\\\"/bundle.js\\\"\u003e\u003c/script\u003e\\nyou may have a crawlability problem.\\nThat does not mean Google can’t render the page. Google can render JavaScript. The issue is that rendering is not the same as clean, fast, reliable discovery. Rendering can be delayed, fail, depend on blocked resources, or be incomplete. Other crawlers may not handle your JavaScript the same way Google does. AI crawlers may be even less patient.\\nFor a serious crawlability audit, gather Google Search Console access, a JavaScript-rendering crawler, server logs if available, XML sitemap access, robots.txt access, framework context, deployment context, and a list of priority URLs by business value.\\nDon’t audit random URLs first. Audit the pages that make money.\\n1. Discovery and Internal Linking\\nCrawlers need paths. SPAs often hide those paths behind client-side behavior, especially when navigation is handled with JavaScript instead of normal links.\\nCheck:\\nImportant pages have unique, crawlable URLs.\\nInternal links use standard anchor tags, like \u003ca href=\\\"/page\\\"\u003e.\\nNavigation does not rely only on onClick, buttons, spans, or JavaScript-only route changes.\\nImportant pages are not only reachable through filters, tabs, search boxes, or infinite scroll.\\nPagination uses crawlable URLs where needed.\\nFaceted pages that should be indexed have distinct URLs.\\nURLs do not rely on hash fragments like #section or old #! patterns for primary page discovery.\\nXML sitemaps include canonical, indexable, 200-status URLs.\\nSitemap URLs do not require JavaScript execution to become meaningful.\\nOrphan pages are identified, especially product, service, blog, and comparison pages.\\nBad pattern:\\n\u003cspan onclick=\\\"navigate('/pricing')\\\"\u003ePricing\u003c/span\u003e\\nBetter pattern:\\n\u003ca href=\\\"/pricing\\\"\u003ePricing\u003c/a\u003e\\nThis sounds basic, but it breaks all the time. If crawlers can’t find the URL, they can’t rank the URL. If AI systems can’t discover the page, they can’t use it as a source.\\n2. Raw HTML vs Rendered HTML\\nThis is the heart of JavaScript crawlability. You need to know what exists before JavaScript runs and what only appears after rendering.\\nCheck:\\nThe raw HTML contains the main topic of the page.\\nThe primary heading is present in the initial HTML.\\nCore body copy is present without waiting for client-side rendering.\\nInternal links are visible in raw HTML or reliably available after render.\\nProduct, service, pricing, author, FAQ, and location content is not hidden behind inaccessible API calls.\\nThe rendered HTML does not remove important content from the initial HTML.\\nThe page still makes sense if JavaScript execution is delayed.\\nThe first meaningful content is not just a blank shell, loading spinner, or placeholder.\\nLook for missing H1s, intro copy, product descriptions, pricing details, reviews, FAQ content, internal links, breadcrumbs, schema markup, canonicals, and robots directives.\\nIf the rendered page is strong but the raw HTML is empty, you may need server-side rendering, static generation, pre-rendering, or a framework-level fix.\\n3. Rendering and Hydration Risks\\nHydration is where a server-rendered or pre-rendered page becomes interactive. It’s also where SEO signals can quietly break.\\nCheck:\\nServer-rendered content matches client-rendered content.\\nHydration does not erase headings, body copy, links, or schema.\\nThe app does not flash one version of metadata and then replace it with another.\\nClient-side state does not rewrite canonical tags incorrectly.\\nLazy-loaded components containing SEO-critical content are rendered early enough to be seen.\\nError states are not served to bots because of blocked APIs or missing headers.\\nImportant content is not dependent on user interaction.\\nRendering does not require cookies, local storage, or logged-in state for public pages.\\nPages do not produce different SEO-critical output across refreshes.\\nA common failure mode: the page appears server-rendered, but hydration fails. Users still see something, so nobody panics. But crawlers may see broken, incomplete, or inconsistent markup.\\nThat’s the kind of issue that wastes weeks because everyone says, “It works on my machine.” Maybe it does. Your machine isn’t the crawler.\\n4. Metadata and Robots Directives\\nMetadata gets messy in SPAs because the client app often controls the document head. Titles, descriptions, canonicals, robots tags, and social metadata may be injected, changed, or removed after load.\\nCheck:\\nEach indexable page has a unique \u003ctitle\u003e in the initial HTML.\\nEach indexable page has a relevant meta description in the initial HTML.\\nCanonical tags are present and correct before client-side JavaScript changes the page.\\nRobots meta tags are correct in raw HTML.\\nThere is no accidental noindex in the initial HTML.\\nJavaScript does not remove or rewrite robots directives after load.\\nOpen Graph and social tags are correct where sharing matters.\\nMetadata templates are not producing duplicated titles across thousands of URLs.\\nRoute changes update metadata correctly without polluting indexable URLs.\\nError pages, filtered pages, and parameter URLs have intentional indexation rules.\\nBe especially careful with noindex. If the raw HTML includes a noindex tag and JavaScript removes it later, you’re playing with fire.\\n5. Canonicals and Duplicate URL Control\\nSingle page applications can create duplicate or near-duplicate URL patterns without anyone noticing. The app may treat multiple routes as the same page. Search engines may not.\\nCheck:\\nCanonicals point to the preferred URL.\\nCanonicals are not injected late in a way that creates inconsistent signals.\\nParameter URLs are handled intentionally.\\nTrailing slash rules are consistent.\\nHTTP and HTTPS versions are consolidated.\\nwww and non-www versions are consolidated.\\nUppercase and lowercase URL variants do not create duplicates.\\nFiltered or sorted versions are indexable only when they should be.\\nClient-side routing does not generate multiple paths for the same content.\\nCanonical tags match sitemap URLs where appropriate.\\nIn a SPA SEO audit, canonicals are not just another checkbox. They help stop your routing system from creating a duplicate-content mess.\\n6. Structured Data and Entity Clarity\\nStructured data helps machines understand what a page is about. That matters for traditional search, rich results, and AI visibility.\\nCheck:\\nJSON-LD schema is present in the initial HTML where possible.\\nSchema matches visible page content.\\nProduct, Article, FAQ, Breadcrumb, Organization, LocalBusiness, SoftwareApplication, or Review schema is used only where appropriate.\\nJavaScript does not inject schema too late or remove it during hydration.\\nSchema is not duplicated across routes.\\nRequired and recommended fields are not empty.\\nEntity names are consistent across page copy, schema, headings, and metadata.\\nBreadcrumb schema matches visible breadcrumbs.\\nFAQ schema, if used, matches visible FAQ content.\\nStructured data is tested on both raw and rendered versions.\\nDo not use schema as decoration. Use it to clarify what already exists on the page.\\n7. AI Crawlability, AEO, and GEO\\nAI search adds another layer to crawlability. Traditional SEO already requires pages to be discoverable, renderable, and trustworthy.\\nAEO and GEO raise another question: can AI systems extract useful answers, entities, and citations from your site without fighting your front end?\\nCheck:\\nCritical content is available in the initial HTML through SSR, SSG, or reliable pre-rendering.\\nPages answer clear questions in plain language.\\nImportant entities are named consistently.\\nProduct, service, feature, audience, location, and pricing information is not hidden behind interactions.\\nFAQs are visible on-page, not only injected after user action.\\nInternal links help crawlers understand topical relationships.\\nSchema supports the visible content.\\nPages are not blocked for non-Google crawlers unless intentional.\\nrobots.txt does not accidentally block resources required to understand the page.\\nKey content can be extracted without clicking, scrolling forever, or running complex JavaScript.\\nMany SPA teams assume “Google can render JavaScript” means everyone can. That is not a safe assumption. For AI visibility, your safest content is content that is easy to fetch, parse, and understand.\\n8. robots.txt, Status Codes, and Crawl Access\\nBefore blaming rendering, make sure crawlers are allowed to access the site in the first place.\\nCheck:\\nrobots.txt does not block important pages.\\nrobots.txt does not block CSS or JavaScript files needed for rendering.\\nAPI endpoints needed to render public content are not blocked if crawlers depend on them.\\nImportant URLs return 200 status codes.\\nRedirect chains are cleaned up.\\nBroken routes do not return soft 404s with 200 status codes.\\nReal 404 pages return 404 status codes.\\nProtected or private app routes are not accidentally indexable.\\nStaging or preview environments are not indexed.\\nProduction pages are not carrying staging noindex rules.\\nJavaScript sites often blur the line between “the route exists in the app” and “the server returns a valid page.” Search engines care about both.\\n9. Core Web Vitals and Performance\\nPerformance is not just a Lighthouse score. It affects crawling, user experience, and conversion.\\nCheck:\\nJavaScript bundles are not excessively large.\\nUnused JavaScript is reduced where possible.\\nMain content is not delayed by heavy client-side rendering.\\nLargest Contentful Paint is not slowed by app shell rendering.\\nInteraction to Next Paint is not hurt by long JavaScript tasks.\\nThird-party scripts are not blocking important rendering.\\nImages are optimized and not dependent on late client-side loading.\\nFonts do not cause major layout shifts.\\nLazy loading does not hide important content from crawlers.\\nCore Web Vitals are reviewed for priority templates, not just the homepage.\\nA SPA can feel fast to your team and still be slow for SEO. If your JavaScript takes too long to deliver the message, the page loses twice: once in search and once in conversion.\\n10. UX and Conversion Risks\\nA SPA SEO audit should not stop at indexability. If a page gets traffic but fails to convert, the business still loses.\\nCheck:\\nThe main value proposition is visible without waiting for full app hydration.\\nCalls to action appear early and work reliably.\\nForms do not break when JavaScript errors occur.\\nPricing, demo, signup, or checkout paths are crawlable and usable.\\nError states are clear and recoverable.\\nPage copy explains what the product or service does without relying on animations.\\nNavigation is understandable without app-specific behavior.\\nMobile users can access the same core content.\\nTracking scripts do not slow the page or interfere with rendering.\\nConversion pages are not accidentally noindexed.\\nThe goal is not a green score. The goal is a page that can be found, understood, trusted, and acted on.\\n11. Framework and Architecture Review\\nDifferent JavaScript setups create different SEO risks. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. But you need to know how each important page is being delivered.\\nCheck:\\nThe rendering mode is known for each important template.\\nServer-side rendering, static generation, client-side rendering, or pre-rendering is documented.\\nDevelopers and SEO teams agree which pages must be indexable.\\nPublic marketing pages are not treated like logged-in app screens.\\nFramework upgrades are tested for rendering changes.\\nRoute-level metadata is tested after deployments.\\nBuild changes do not accidentally remove pre-rendered content.\\nAPI failures do not produce thin indexable pages.\\nError boundaries do not hide content from crawlers.\\nSEO checks are included before major releases.\\nThe exact fix depends on the stack. The audit pattern stays the same: prove what crawlers get, then fix the gap.\\n12. Google Search Console Checks\\nGoogle Search Console will not tell you everything, but it will show useful symptoms.\\nCheck:\\nImportant URLs are indexed.\\nImportant URLs are not stuck in “Discovered, currently not indexed” without explanation.\\nImportant URLs are not excluded by noindex.\\nGoogle’s selected canonical matches your intended canonical.\\nCrawled pages show the expected content.\\nPage indexing reports are reviewed by template type.\\nSitemap submissions match your indexable URL strategy.\\nPerformance data is reviewed for pages that should drive revenue.\\nQuery data is checked for technical GEO, AEO, and crawlability demand.\\nDrops are compared against deployments, migrations, and framework changes.\\nTreat Search Console as evidence, not a magic oracle. If impressions are weak, pages are excluded, or Google chooses unexpected canonicals, your JavaScript delivery may be part of the problem.\\n13. Log File and Bot Behavior Review\\nIf you have log access, use it. Logs show what crawlers actually did.\\nCheck:\\nGooglebot is crawling important URLs.\\nImportant sections are not being ignored.\\nCrawl frequency changed after a migration or release.\\nBots are hitting redirected or broken routes too often.\\nServer responses for crawlers are clean and consistent.\\nStatic assets needed for rendering are accessible.\\nNon-Google crawlers are not accidentally blocked if AI visibility matters.\\nCrawl waste is reduced on low-value routes.\\nMoney pages receive crawl attention.\\nBot behavior aligns with your sitemap and internal linking strategy.\\nLogs are useful because they show reality: not what the crawler could do, not what the framework should do, but what actually happened.\\n14. Copy and Content Extraction\\nJavaScript SEO is not only technical. Once crawlers reach the page, they still need meaningful content.\\nCheck:\\nThe page clearly states what the company, product, or service does.\\nThe target audience is obvious.\\nThe problem, solution, and outcome are explained.\\nImportant terms are written naturally in visible copy.\\nHeadings describe the page, not just marketing slogans.\\nFeature descriptions are not hidden inside components that require JavaScript to populate.\\nFAQs answer real buyer or technical questions.\\nComparison and alternative pages include enough context to be useful.\\nThin pages are improved or removed from indexation.\\nAI extraction would produce an accurate summary of the page.\\nCrawlability gets the page seen. Good copy gets the page understood. Clear conversion paths get the buyer moving. You need all three.\\n15. CI and Release Monitoring\\nA one-time audit helps. A repeatable process protects you from regressions.\\nCheck:\\nPriority URLs are tested before major releases.\\nRaw HTML snapshots are compared over time.\\nRendered HTML snapshots are compared over time.\\nMetadata changes are monitored.\\nCanonical changes are monitored.\\nRobots directives are monitored.\\nSchema presence is tested.\\nInternal links are crawled after deployments.\\nPerformance regressions are flagged.\\nSEO-critical templates have QA requirements.\\nJavaScript SEO problems often appear after innocent changes: a route refactor, framework upgrade, hydration fix, analytics script, redesign, CMS change, or deployment config update. None of those sound like SEO projects. They can still break SEO.\\nHow Savage Audit Fits Naturally\\nSavage Audit is built for exactly this kind of problem.\\nJavaScript-heavy websites usually sit between three teams:\\nDevelopers care about architecture, deployment, performance, and maintainability.\\nSEO teams care about crawlability, indexation, rankings, and structured data.\\nFounders and marketers care about pipeline, demos, signups, and revenue.\\nEveryone can be right and the site can still be broken.\\nSavage Audit helps identify JavaScript crawlability problems, single page application SEO issues, raw HTML vs rendered HTML gaps, metadata and canonical failures, AI crawlability risks, technical SEO blockers, UX problems, copy gaps, and prioritized fixes your dev team can actually use.\\nFor related technical checks, see the Technical GEO Audit Checklist, the Website Audit Tool for Developers, and the guide to LLMs.txt vs Robots.txt vs Structured Data.\\nThe point is not to shame the stack. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. The point is to stop pretending the browser experience is the same as crawler access.\\nFinal Takeaway\\nYour single page application can look beautiful in the browser and still be a search liability.\\nDo not start with vanity metrics. Do not start by rewriting every headline. Do not assume “Google can render JavaScript” means your crawlability is fine.\\nStart with proof.\\nCompare raw HTML against rendered HTML. Check internal links. Verify metadata. Test schema. Review robots directives. Look at crawl access. Then check whether AI crawlers can extract the same core content your users see.\\nIf bots cannot read your app, buyers may never find it. That is the real JavaScript SEO audit.\",\"wordCount\":2959,\"about\":[{\"@type\":\"Thing\",\"name\":\"Technical Teardowns\"},{\"@type\":\"Thing\",\"name\":\"Technical SEO \u0026 Website Audits\"}],\"author\":{\"@type\":\"Person\",\"name\":\"SavageAudit Team\",\"knowsAbout\":[\"SEO audits\",\"AI visibility\",\"UX critique\",\"conversion copy\"]},\"publisher\":{\"@type\":\"Organization\",\"@id\":\"https://savageaudit.com/#organization\",\"name\":\"SavageAudit\",\"url\":\"https://savageaudit.com/\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://savageaudit.com/logo.png\"}},\"mainEntityOfPage\":{\"@type\":\"WebPage\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#webpage\"},\"articleSection\":\"Technical Teardowns\",\"keywords\":\"javascript seo audit, single page application seo, crawlability audit, javascript crawlability, technical seo crawlability, spa seo audit, ai crawlability audit, Technical Teardowns, Technical SEO \u0026 Website Audits, SavageAudit\",\"timeRequired\":\"PT22M\"},{\"@context\":\"https://schema.org\",\"@type\":\"BreadcrumbList\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https://savageaudit.com/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Blog\",\"item\":\"https://savageaudit.com/blog\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\",\"item\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\"}]},{\"@context\":\"https://schema.org\",\"@type\":\"FAQPage\",\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#faq\",\"isPartOf\":{\"@id\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps#webpage\"},\"mainEntity\":[{\"@type\":\"Question\",\"name\":\"What is a JavaScript SEO audit?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"A JavaScript SEO audit checks whether a JavaScript-heavy website can be discovered, rendered, indexed, understood, and ranked by search engines. It compares raw HTML, rendered HTML, metadata, internal links, schema, status codes, performance, and crawl access.\"}},{\"@type\":\"Question\",\"name\":\"What is an AI crawlability audit checklist?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"An AI crawlability audit checklist verifies whether AI crawlers and answer engines can extract useful content from your site. It focuses on raw HTML access, clear copy, structured data, crawl permissions, internal links, and whether important content requires complex JavaScript execution.\"}},{\"@type\":\"Question\",\"name\":\"How do I check Backbone.js crawlability?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"For Backbone.js crawlability, start with routing and raw HTML. Check whether important URLs return meaningful content on direct server requests, whether internal links use crawlable anchors, and whether metadata is available before client-side DOM manipulation.\"}},{\"@type\":\"Question\",\"name\":\"When should I run a SPA SEO audit?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Run a SPA SEO audit before launches, migrations, redesigns, framework upgrades, and major routing changes. Also run one after unexplained organic traffic drops, indexation problems, canonical issues, or performance regressions.\"}},{\"@type\":\"Question\",\"name\":\"Why is my SPA indexed but not ranking well?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"An SPA can be indexed but still rank poorly if crawlers see thin raw HTML, delayed content, weak internal links, slow rendering, inconsistent metadata, or confusing canonicals. Indexing does not prove search engines fully understood the page.\"}}]}]"])</script><script>self.__next_f.push([1,"16:[\"$\",\"main\",null,{\"children\":[[\"$\",\"script\",null,{\"type\":\"application/ld+json\",\"dangerouslySetInnerHTML\":{\"__html\":\"$1d\"}}],\"$L1e\",\"$L1f\"]}]\n1e:[\"$\",\"div\",null,{\"className\":\"blog-hero-glow\",\"aria-hidden\":\"true\",\"children\":[[\"$\",\"span\",null,{}],[\"$\",\"span\",null,{}],[\"$\",\"span\",null,{}]]}]\n"])</script><script>self.__next_f.push([1,"1f:[\"$\",\"article\",null,{\"className\":\"blog-post-shell\",\"children\":[[\"$\",\"section\",null,{\"className\":\"blog-post-hero\",\"aria-labelledby\":\"blog-post-title\",\"children\":[\"$\",\"div\",null,{\"className\":\"container blog-post-hero-inner\",\"children\":[[\"$\",\"nav\",null,{\"aria-label\":\"Breadcrumb\",\"className\":\"blog-breadcrumb\",\"children\":[\"$\",\"ol\",null,{\"children\":[[\"$\",\"li\",null,{\"children\":[\"$\",\"$L4\",null,{\"href\":\"/\",\"title\":\"Go to SavageAudit home\",\"children\":\"Home\"}]}],[\"$\",\"li\",null,{\"aria-hidden\":\"true\",\"children\":\"/\"}],[\"$\",\"li\",null,{\"children\":[\"$\",\"$L4\",null,{\"href\":\"/blog\",\"title\":\"Go to SavageAudit blog\",\"children\":\"Blog\"}]}],[\"$\",\"li\",null,{\"aria-hidden\":\"true\",\"children\":\"/\"}],[\"$\",\"li\",null,{\"aria-current\":\"page\",\"title\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\",\"children\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\"}]]}]}],[\"$\",\"header\",null,{\"className\":\"blog-post-hero-grid\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-post-copy\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-category-chips\",\"aria-label\":\"Article categories\",\"children\":[null,[[\"$\",\"span\",\"technical-teardowns\",{\"className\":\"badge\",\"children\":\"Technical Teardowns\"}]]]}],[\"$\",\"p\",null,{\"className\":\"mono blog-post-meta-line\",\"children\":[[\"$\",\"time\",null,{\"dateTime\":\"2026-07-17T12:00:00Z\",\"children\":\"Jul 17, 2026\"}],\" / \",22,\" min read\"]}],[\"$\",\"h1\",null,{\"id\":\"blog-post-title\",\"children\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\"}],[\"$\",\"p\",null,{\"className\":\"hero-sub\",\"children\":\"Use this JavaScript SEO audit checklist to check SPA crawlability, raw HTML, rendering, metadata, AI visibility, UX, and conversion risks before rankings suffer.\"}],[\"$\",\"div\",null,{\"className\":\"blog-author-share-row\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-author-card\",\"children\":[[\"$\",\"span\",null,{\"className\":\"blog-author-avatar\",\"aria-hidden\":\"true\",\"children\":\"S\"}],[\"$\",\"div\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"mono blog-author-label\",\"children\":\"Written by\"}],[\"$\",\"strong\",null,{\"children\":\"SavageAudit Team\"}],[\"$\",\"span\",null,{\"children\":\"Product \u0026 Research\"}]]}]]}],[\"$\",\"$L20\",null,{\"title\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\",\"url\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\"}]]}]]}],[\"$\",\"aside\",null,{\"className\":\"blog-article-brief\",\"aria-label\":\"Article brief\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-brief-top\",\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"mono blog-brief-eyebrow\",\"children\":\"Article brief\"}],[\"$\",\"h2\",null,{\"children\":\"Public-proof reading map\"}]]}],[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"Audit Intel\"}]]}],[\"$\",\"div\",null,{\"className\":\"blog-brief-grid\",\"children\":[[\"$\",\"div\",\"Category\",{\"className\":\"blog-brief-row\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Category\"}],[\"$\",\"strong\",null,{\"children\":\"Technical Teardowns\"}]]}],[\"$\",\"div\",\"Read time\",{\"className\":\"blog-brief-row\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Read time\"}],[\"$\",\"strong\",null,{\"children\":\"22 min\"}]]}],[\"$\",\"div\",\"Author\",{\"className\":\"blog-brief-row\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Author\"}],[\"$\",\"strong\",null,{\"children\":\"SavageAudit Team\"}]]}],[\"$\",\"div\",\"Published\",{\"className\":\"blog-brief-row\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Published\"}],[\"$\",\"strong\",null,{\"children\":\"Jul 17, 2026\"}]]}]]}],[\"$\",\"div\",null,{\"className\":\"blog-brief-angle\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"SavageAudit angle\"}],[\"$\",\"p\",null,{\"children\":\"Use the public web like a buyer would: check search, AI answers, social proof, competitor context, and conversion trust in one pass.\"}]]}]]}]]}]]}]}],[\"$\",\"div\",null,{\"className\":\"container blog-post-media-shell\",\"children\":[\"$\",\"figure\",null,{\"className\":\"blog-post-image\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-post-image-frame\",\"children\":[\"$\",\"$L5\",null,{\"src\":\"https://cdn.sanity.io/images/elyr32gq/production/46535ddf9afe2e9a2b8161a0d870b2ace3418e0b-1376x768.jpg?rect=6,0,1365,768\u0026w=1600\u0026h=900\u0026fit=crop\u0026auto=format\",\"alt\":\"Dark abstract website audit dashboard showing JavaScript crawlability checks and orange warning panels.\",\"title\":\"Dark abstract website audit dashboard showing JavaScript crawlability checks and orange warning panels.\",\"width\":1600,\"height\":900,\"sizes\":\"(max-width: 1100px) 100vw, 1180px\",\"priority\":true,\"unoptimized\":true}]}],null]}]}],\"$L21\"]}]\n"])</script><script>self.__next_f.push([1,"21:[\"$\",\"div\",null,{\"className\":\"container blog-article-layout\",\"children\":[[\"$\",\"aside\",null,{\"className\":\"blog-article-rail blog-article-rail--left\",\"children\":[\"$\",\"div\",null,{\"className\":\"blog-article-rail-sticky\",\"children\":[\"$\",\"section\",null,{\"className\":\"blog-reader-rail-panel\",\"aria-label\":\"Article navigation\",\"children\":[\"$\",\"$L22\",null,{\"outline\":[{\"id\":\"short-answer-what-are-you-auditing\",\"title\":\"Short Answer: What Are You Auditing?\",\"level\":2},{\"id\":\"who-this-is-for\",\"title\":\"Who This Is For\",\"level\":2},{\"id\":\"what-to-check-first\",\"title\":\"What to Check First\",\"level\":2},{\"id\":\"1-discovery-and-internal-linking\",\"title\":\"1. Discovery and Internal Linking\",\"level\":2},{\"id\":\"2-raw-html-vs-rendered-html\",\"title\":\"2. Raw HTML vs Rendered HTML\",\"level\":2},{\"id\":\"3-rendering-and-hydration-risks\",\"title\":\"3. Rendering and Hydration Risks\",\"level\":2},{\"id\":\"4-metadata-and-robots-directives\",\"title\":\"4. Metadata and Robots Directives\",\"level\":2},{\"id\":\"5-canonicals-and-duplicate-url-control\",\"title\":\"5. Canonicals and Duplicate URL Control\",\"level\":2},{\"id\":\"6-structured-data-and-entity-clarity\",\"title\":\"6. Structured Data and Entity Clarity\",\"level\":2},{\"id\":\"7-ai-crawlability-aeo-and-geo\",\"title\":\"7. AI Crawlability, AEO, and GEO\",\"level\":2},{\"id\":\"8-robots-txt-status-codes-and-crawl-access\",\"title\":\"8. robots.txt, Status Codes, and Crawl Access\",\"level\":2},{\"id\":\"9-core-web-vitals-and-performance\",\"title\":\"9. Core Web Vitals and Performance\",\"level\":2},{\"id\":\"10-ux-and-conversion-risks\",\"title\":\"10. UX and Conversion Risks\",\"level\":2},{\"id\":\"11-framework-and-architecture-review\",\"title\":\"11. Framework and Architecture Review\",\"level\":2},{\"id\":\"12-google-search-console-checks\",\"title\":\"12. Google Search Console Checks\",\"level\":2},{\"id\":\"13-log-file-and-bot-behavior-review\",\"title\":\"13. Log File and Bot Behavior Review\",\"level\":2},{\"id\":\"14-copy-and-content-extraction\",\"title\":\"14. Copy and Content Extraction\",\"level\":2},{\"id\":\"15-ci-and-release-monitoring\",\"title\":\"15. CI and Release Monitoring\",\"level\":2},{\"id\":\"how-savage-audit-fits-naturally\",\"title\":\"How Savage Audit Fits Naturally\",\"level\":2},{\"id\":\"final-takeaway\",\"title\":\"Final Takeaway\",\"level\":2}]}]}]}]}],[\"$\",\"div\",null,{\"className\":\"blog-article-content\",\"children\":[[\"$\",\"section\",null,{\"className\":\"blog-mobile-reader\",\"aria-label\":\"Mobile article navigation\",\"children\":[\"$\",\"$L22\",null,{\"outline\":\"$21:props:children:0:props:children:props:children:props:children:props:outline\"}]}],[\"$\",\"section\",null,{\"className\":\"portable-content\",\"aria-label\":\"Article content\",\"children\":[[\"$\",\"section\",null,{\"className\":\"blog-answer-summary\",\"aria-label\":\"Direct answer\",\"children\":[[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"Short answer\"}],[\"$\",\"p\",null,{\"children\":\"A JavaScript SEO audit checks whether search engines, AI crawlers, and users can access the same important SPA content. Start by comparing raw HTML, rendered HTML, metadata, internal links, schema, crawl access, and conversion-critical page elements.\"}]]}],[[\"$\",\"p\",\"b2\",{\"children\":[\"A JavaScript SEO audit is a reality check.\"]}],[\"$\",\"p\",\"b5\",{\"children\":[\"It answers one simple question: \",[\"$\",\"strong\",\"s4\",{\"children\":[\"can search engines, AI crawlers, and real users all access the same important content on your JavaScript-heavy website?\"]}]]}],[\"$\",\"p\",\"b7\",{\"children\":[\"Your site can look perfect in a browser and still be hard for crawlers to discover, render, understand, or trust. If your key content, internal links, metadata, and schema only appear after client-side JavaScript runs, you may not have a content problem. You may have a delivery problem.\"]}],[\"$\",\"p\",\"b9\",{\"children\":[\"Before you blame rankings, rewrite every headline, or assume the algorithm hates you, check whether crawlers can actually see what you’re trying to rank.\"]}],[\"$\",\"h2\",\"bb\",{\"id\":\"short-answer-what-are-you-auditing\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"Short Answer: What Are You Auditing?\"]}],[\"$\",\"p\",\"bf\",{\"children\":[\"A proper \",\"$L23\",\" compares what a user sees in the browser with what crawlers can access before and after JavaScript rendering.\"]}],\"$L24\",\"$L25\",\"$L26\",\"$L27\",\"$L28\",\"$L29\",\"$L2a\",\"$L2b\",\"$L2c\",\"$L2d\",\"$L2e\",\"$L2f\",\"$L30\",\"$L31\",\"$L32\",\"$L33\",\"$L34\",\"$L35\",\"$L36\",\"$L37\",\"$L38\",\"$L39\",\"$L3a\",\"$L3b\",\"$L3c\",\"$L3d\",\"$L3e\",\"$L3f\",\"$L40\",\"$L41\",\"$L42\",\"$L43\",\"$L44\",\"$L45\",\"$L46\",\"$L47\",\"$L48\",\"$L49\",\"$L4a\",\"$L4b\",\"$L4c\",\"$L4d\",\"$L4e\",\"$L4f\",\"$L50\",\"$L51\",\"$L52\",\"$L53\",\"$L54\",\"$L55\",\"$L56\",\"$L57\",\"$L58\",\"$L59\",\"$L5a\",\"$L5b\",\"$L5c\",\"$L5d\",\"$L5e\",\"$L5f\",\"$L60\",\"$L61\",\"$L62\",\"$L63\",\"$L64\",\"$L65\",\"$L66\",\"$L67\",\"$L68\",\"$L69\",\"$L6a\",\"$L6b\",\"$L6c\",\"$L6d\",\"$L6e\",\"$L6f\",\"$L70\",\"$L71\",\"$L72\",\"$L73\",\"$L74\",\"$L75\",\"$L76\",\"$L77\",\"$L78\",\"$L79\",\"$L7a\",\"$L7b\",\"$L7c\",\"$L7d\",\"$L7e\",\"$L7f\",\"$L80\",\"$L81\",\"$L82\",\"$L83\",\"$L84\",\"$L85\",\"$L86\",\"$L87\",\"$L88\",\"$L89\",\"$L8a\",\"$L8b\",\"$L8c\",\"$L8d\",\"$L8e\",\"$L8f\",\"$L90\",\"$L91\",\"$L92\",\"$L93\",\"$L94\",\"$L95\",\"$L96\"]]}],\"$L97\",\"$L98\",\"$L99\",\"$L9a\",\"$L9b\"]}]]}]\n"])</script><script>self.__next_f.push([1,"23:[\"$\",\"strong\",\"sd\",{\"children\":[\"JavaScript SEO audit\"]}]\n24:[\"$\",\"p\",\"bh\",{\"children\":[\"You’re looking for five types of problems:\"]}]\n25:[\"$\",\"ul\",\"bk-parent\",{\"children\":[[\"$\",\"li\",\"bk\",{\"children\":[[\"$\",\"strong\",\"si\",{\"children\":[\"Discovery gaps:\"]}],\" crawlers can’t find your important URLs.\"]}],[\"$\",\"li\",\"bn\",{\"children\":[[\"$\",\"strong\",\"sl\",{\"children\":[\"Rendering gaps:\"]}],\" raw HTML is empty, thin, or missing key content.\"]}],[\"$\",\"li\",\"bq\",{\"children\":[[\"$\",\"strong\",\"so\",{\"children\":[\"Metadata issues:\"]}],\" titles, canonicals, robots tags, or schema show up too late or get overwritten.\"]}],[\"$\",\"li\",\"bt\",{\"children\":[[\"$\",\"strong\",\"sr\",{\"children\":[\"AI crawlability risks:\"]}],\" AI crawlers may not execute your JavaScript before extracting content.\"]}],[\"$\",\"li\",\"bw\",{\"children\":[[\"$\",\"strong\",\"su\",{\"children\":[\"UX and conversion drag:\"]}],\" large bundles, slow rendering, hydration issues, and front-end bugs hurt users too.\"]}]]}]\n26:[\"$\",\"p\",\"by\",{\"children\":[\"The blunt version: if your single page app makes the browser do all the work, prove bots can still understand the page. Don’t assume it.\"]}]\n27:[\"$\",\"h2\",\"b10\",{\"id\":\"who-this-is-for\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"Who This Is For\"]}]\n28:[\"$\",\"p\",\"b12\",{\"children\":[\"This guide is for teams running JavaScript-heavy websites where organic visibility matters.\"]}]\n29:[\"$\",\"p\",\"b14\",{\"children\":[\"That includes:\"]}]\n2a:[\"$\",\"ul\",\"b17-parent\",{\"children\":[[\"$\",\"li\",\"b17\",{\"children\":[[\"$\",\"strong\",\"s15\",{\"children\":[\"Developers and engineering leads\"]}],\" working with React, Vue, Angular, Next.js, Nuxt, Backbone.js, or custom JavaScript apps.\"]}],[\"$\",\"li\",\"b1a\",{\"children\":[[\"$\",\"strong\",\"s18\",{\"children\":[\"Technical founders\"]}],\" who shipped a polished product but can’t figure out why organic traffic, demo requests, or signups are flat.\"]}],[\"$\",\"li\",\"b1d\",{\"children\":[[\"$\",\"strong\",\"s1b\",{\"children\":[\"SEO teams\"]}],\" responsible for SPA SEO, technical SEO crawlability, AEO, GEO, and AI visibility.\"]}],[\"$\",\"li\",\"b1g\",{\"children\":[[\"$\",\"strong\",\"s1e\",{\"children\":[\"Growth and marketing teams\"]}],\" who suspect the content isn’t the real issue.\"]}],[\"$\",\"li\",\"b1j\",{\"children\":[[\"$\",\"strong\",\"s1h\",{\"children\":[\"Agencies and consultants\"]}],\" auditing modern websites where “view source” and “inspect element” tell two very different stories.\"]}]]}]\n2b:[\"$\",\"p\",\"b1l\",{\"children\":[\"This is not a meta description tune-up. This is a delivery audit.\"]}]\n2c:[\"$\",\"h2\",\"b1n\",{\"id\":\"what-to-check-first\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"What to Check First\"]}]\n2d:[\"$\",\"p\",\"b1p\",{\"children\":[\"Pick one important page from your SPA or JavaScript-heavy site. Not a random page. Choose a page that should bring in qualified traffic, such as a product page, service page, pricing page, comparison page, location page, blog post, or use case page.\"]}]\n2e:[\"$\",\"p\",\"b1r\",{\"children\":[\"Now compare three versions of that page:\"]}]\n2f:[\"$\",\"ol\",\"b1t-parent\",{\"children\":[[\"$\",\"li\",\"b1t\",{\"children\":[[\"$\",\"strong\",\"s1s\",{\"children\":[\"What a normal user sees in Chrome\"]}]]}],[\"$\",\"li\",\"b1v\",{\"children\":[[\"$\",\"strong\",\"s1u\",{\"children\":[\"What appears in the raw HTML source\"]}]]}],[\"$\",\"li\",\"b1x\",{\"children\":[[\"$\",\"strong\",\"s1w\",{\"children\":[\"What appears after a rendered crawl or headless browser render\"]}]]}]]}]\n30:[\"$\",\"p\",\"b1z\",{\"children\":[\"You’re looking for the gap between them.\"]}]\n31:[\"$\",\"p\",\"b21\",{\"children\":[\"If Chrome shows a full, useful page but the raw HTML looks like this:\"]}]\n32:[\"$\",\"p\",\"b23\",{\"children\":[\"\u003cdiv id=\\\"root\\\"\u003e\u003c/div\u003e\",[\"$\",\"br\",\"node-1\",{}],\"\u003cscript src=\\\"/bundle.js\\\"\u003e\u003c/script\u003e\"]}]\n33:[\"$\",\"p\",\"b25\",{\"children\":[\"you may have a crawlability problem.\"]}]\n34:[\"$\",\"p\",\"b27\",{\"children\":[\"That does not mean Google can’t render the page. Google can render JavaScript. The issue is that rendering is not the same as clean, fast, reliable discovery. Rendering can be delayed, fail, depend on blocked resources, or be incomplete. Other crawlers may not handle your JavaScript the same way G"])</script><script>self.__next_f.push([1,"oogle does. AI crawlers may be even less patient.\"]}]\n35:[\"$\",\"p\",\"b2b\",{\"children\":[\"For a serious \",[\"$\",\"strong\",\"s29\",{\"children\":[\"crawlability audit\"]}],\", gather Google Search Console access, a JavaScript-rendering crawler, server logs if available, XML sitemap access, robots.txt access, framework context, deployment context, and a list of priority URLs by business value.\"]}]\n36:[\"$\",\"p\",\"b2d\",{\"children\":[\"Don’t audit random URLs first. Audit the pages that make money.\"]}]\n37:[\"$\",\"h2\",\"b2f\",{\"id\":\"1-discovery-and-internal-linking\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"1. Discovery and Internal Linking\"]}]\n38:[\"$\",\"p\",\"b2h\",{\"children\":[\"Crawlers need paths. SPAs often hide those paths behind client-side behavior, especially when navigation is handled with JavaScript instead of normal links.\"]}]\n39:[\"$\",\"p\",\"b2j\",{\"children\":[\"Check:\"]}]\n3a:[\"$\",\"ul\",\"b2l-parent\",{\"children\":[[\"$\",\"li\",\"b2l\",{\"children\":[\"Important pages have unique, crawlable URLs.\"]}],[\"$\",\"li\",\"b2p\",{\"children\":[\"Internal links use standard anchor tags, like \",[\"$\",\"code\",\"s2n\",{\"children\":[\"\u003ca href=\\\"/page\\\"\u003e\"]}],\".\"]}],[\"$\",\"li\",\"b2t\",{\"children\":[\"Navigation does not rely only on \",[\"$\",\"code\",\"s2r\",{\"children\":[\"onClick\"]}],\", buttons, spans, or JavaScript-only route changes.\"]}],[\"$\",\"li\",\"b2v\",{\"children\":[\"Important pages are not only reachable through filters, tabs, search boxes, or infinite scroll.\"]}],[\"$\",\"li\",\"b2x\",{\"children\":[\"Pagination uses crawlable URLs where needed.\"]}],[\"$\",\"li\",\"b2z\",{\"children\":[\"Faceted pages that should be indexed have distinct URLs.\"]}],[\"$\",\"li\",\"b35\",{\"children\":[\"URLs do not rely on hash fragments like \",[\"$\",\"code\",\"s31\",{\"children\":[\"#section\"]}],\" or old \",[\"$\",\"code\",\"s33\",{\"children\":[\"#!\"]}],\" patterns for primary page discovery.\"]}],[\"$\",\"li\",\"b37\",{\"children\":[\"XML sitemaps include canonical, indexable, 200-status URLs.\"]}],[\"$\",\"li\",\"b39\",{\"children\":[\"Sitemap URLs do not require JavaScript execution to become meaningful.\"]}],[\"$\",\"li\",\"b3b\",{\"children\":[\"Orphan pages are identified, especially product, service, blog, and comparison pages.\"]}]]}]\n3b:[\"$\",\"p\",\"b3d\",{\"children\":[\"Bad pattern:\"]}]\n3c:[\"$\",\"p\",\"b3f\",{\"children\":[\"\u003cspan onclick=\\\"navigate('/pricing')\\\"\u003ePricing\u003c/span\u003e\"]}]\n3d:[\"$\",\"p\",\"b3h\",{\"children\":[\"Better pattern:\"]}]\n3e:[\"$\",\"p\",\"b3j\",{\"children\":[\"\u003ca href=\\\"/pricing\\\"\u003ePricing\u003c/a\u003e\"]}]\n3f:[\"$\",\"p\",\"b3l\",{\"children\":[\"This sounds basic, but it breaks all the time. If crawlers can’t find the URL, they can’t rank the URL. If AI systems can’t discover the page, they can’t use it as a source.\"]}]\n40:[\"$\",\"h2\",\"b3n\",{\"id\":\"2-raw-html-vs-rendered-html\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"2. Raw HTML vs Rendered HTML\"]}]\n41:[\"$\",\"p\",\"b3r\",{\"children\":[\"This is the heart of \",[\"$\",\"strong\",\"s3p\",{\"children\":[\"JavaScript crawlability\"]}],\". You need to know what exists before JavaScript runs and what only appears after rendering.\"]}]\n42:[\"$\",\"p\",\"b3t\",{\"children\":[\"Check:\"]}]\n43:[\"$\",\"ul\",\"b3v-parent\",{\"children\":[[\"$\",\"li\",\"b3v\",{\"children\":[\"The raw HTML contains the main topic of the page.\"]}],[\"$\",\"li\",\"b3x\",{\"children\":[\"The primary heading is present in the initial HTML.\"]}],[\"$\",\"li\",\"b3z\",{\"children\":[\"Core body copy is present without waiting for client-side rendering.\"]}],[\"$\",\"li\",\"b41\",{\"children\":[\"Internal links are visible in raw HTML or reliably available after render.\"]}],[\"$\",\"li\",\"b43\",{\"children\":[\"Product, service, pricing, author, FAQ, and location content is not hidden behind inaccessible API calls.\"]}],[\"$\",\"li\",\"b45\",{\"children\":[\"The rendered HTML does not remove important content from the initial HTML.\"]}],[\"$\",\"li\",\"b47\",{\"children\":[\"The page still makes sense if JavaScript execution is delayed.\"]}],[\"$\",\"li\",\"b49\",{\"children\":[\"The first meaningful content is not just a blank shell, loading spinner, or placeholder.\"]}]]}]\n44:[\"$\",\"p\",\"b4b\",{\"children\":[\"Look for missing H1s, intro copy, product descriptions, pricing details, reviews, FAQ content, internal links, breadcrumbs, schema markup, ca"])</script><script>self.__next_f.push([1,"nonicals, and robots directives.\"]}]\n45:[\"$\",\"p\",\"b4d\",{\"children\":[\"If the rendered page is strong but the raw HTML is empty, you may need server-side rendering, static generation, pre-rendering, or a framework-level fix.\"]}]\n46:[\"$\",\"h2\",\"b4f\",{\"id\":\"3-rendering-and-hydration-risks\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"3. Rendering and Hydration Risks\"]}]\n47:[\"$\",\"p\",\"b4h\",{\"children\":[\"Hydration is where a server-rendered or pre-rendered page becomes interactive. It’s also where SEO signals can quietly break.\"]}]\n48:[\"$\",\"p\",\"b4j\",{\"children\":[\"Check:\"]}]\n49:[\"$\",\"ul\",\"b4l-parent\",{\"children\":[[\"$\",\"li\",\"b4l\",{\"children\":[\"Server-rendered content matches client-rendered content.\"]}],[\"$\",\"li\",\"b4n\",{\"children\":[\"Hydration does not erase headings, body copy, links, or schema.\"]}],[\"$\",\"li\",\"b4p\",{\"children\":[\"The app does not flash one version of metadata and then replace it with another.\"]}],[\"$\",\"li\",\"b4r\",{\"children\":[\"Client-side state does not rewrite canonical tags incorrectly.\"]}],[\"$\",\"li\",\"b4t\",{\"children\":[\"Lazy-loaded components containing SEO-critical content are rendered early enough to be seen.\"]}],[\"$\",\"li\",\"b4v\",{\"children\":[\"Error states are not served to bots because of blocked APIs or missing headers.\"]}],[\"$\",\"li\",\"b4x\",{\"children\":[\"Important content is not dependent on user interaction.\"]}],[\"$\",\"li\",\"b4z\",{\"children\":[\"Rendering does not require cookies, local storage, or logged-in state for public pages.\"]}],[\"$\",\"li\",\"b51\",{\"children\":[\"Pages do not produce different SEO-critical output across refreshes.\"]}]]}]\n4a:[\"$\",\"p\",\"b53\",{\"children\":[\"A common failure mode: the page appears server-rendered, but hydration fails. Users still see something, so nobody panics. But crawlers may see broken, incomplete, or inconsistent markup.\"]}]\n4b:[\"$\",\"p\",\"b55\",{\"children\":[\"That’s the kind of issue that wastes weeks because everyone says, “It works on my machine.” Maybe it does. Your machine isn’t the crawler.\"]}]\n4c:[\"$\",\"h2\",\"b57\",{\"id\":\"4-metadata-and-robots-directives\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"4. Metadata and Robots Directives\"]}]\n4d:[\"$\",\"p\",\"b59\",{\"children\":[\"Metadata gets messy in SPAs because the client app often controls the document head. Titles, descriptions, canonicals, robots tags, and social metadata may be injected, changed, or removed after load.\"]}]\n4e:[\"$\",\"p\",\"b5b\",{\"children\":[\"Check:\"]}]\n4f:[\"$\",\"ul\",\"b5f-parent\",{\"children\":[[\"$\",\"li\",\"b5f\",{\"children\":[\"Each indexable page has a unique \",[\"$\",\"code\",\"s5d\",{\"children\":[\"\u003ctitle\u003e\"]}],\" in the initial HTML.\"]}],[\"$\",\"li\",\"b5h\",{\"children\":[\"Each indexable page has a relevant meta description in the initial HTML.\"]}],[\"$\",\"li\",\"b5j\",{\"children\":[\"Canonical tags are present and correct before client-side JavaScript changes the page.\"]}],[\"$\",\"li\",\"b5l\",{\"children\":[\"Robots meta tags are correct in raw HTML.\"]}],[\"$\",\"li\",\"b5p\",{\"children\":[\"There is no accidental \",[\"$\",\"code\",\"s5n\",{\"children\":[\"noindex\"]}],\" in the initial HTML.\"]}],[\"$\",\"li\",\"b5r\",{\"children\":[\"JavaScript does not remove or rewrite robots directives after load.\"]}],[\"$\",\"li\",\"b5t\",{\"children\":[\"Open Graph and social tags are correct where sharing matters.\"]}],[\"$\",\"li\",\"b5v\",{\"children\":[\"Metadata templates are not producing duplicated titles across thousands of URLs.\"]}],[\"$\",\"li\",\"b5x\",{\"children\":[\"Route changes update metadata correctly without polluting indexable URLs.\"]}],[\"$\",\"li\",\"b5z\",{\"children\":[\"Error pages, filtered pages, and parameter URLs have intentional indexation rules.\"]}]]}]\n50:[\"$\",\"p\",\"b65\",{\"children\":[\"Be especially careful with \",[\"$\",\"code\",\"s61\",{\"children\":[\"noindex\"]}],\". If the raw HTML includes a \",[\"$\",\"code\",\"s63\",{\"children\":[\"noindex\"]}],\" tag and JavaScript removes it later, you’re playing with fire.\"]}]\n51:[\"$\",\"h2\",\"b67\",{\"id\":\"5-canonicals-and-duplicate-url-control\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"5. Canonicals and Duplicate URL Control\"]}]\n52:[\"$\",\"p\",\"b69\",{\"children\":[\"Single page applications can create duplicate or n"])</script><script>self.__next_f.push([1,"ear-duplicate URL patterns without anyone noticing. The app may treat multiple routes as the same page. Search engines may not.\"]}]\n53:[\"$\",\"p\",\"b6b\",{\"children\":[\"Check:\"]}]\n54:[\"$\",\"ul\",\"b6d-parent\",{\"children\":[[\"$\",\"li\",\"b6d\",{\"children\":[\"Canonicals point to the preferred URL.\"]}],[\"$\",\"li\",\"b6f\",{\"children\":[\"Canonicals are not injected late in a way that creates inconsistent signals.\"]}],[\"$\",\"li\",\"b6h\",{\"children\":[\"Parameter URLs are handled intentionally.\"]}],[\"$\",\"li\",\"b6j\",{\"children\":[\"Trailing slash rules are consistent.\"]}],[\"$\",\"li\",\"b6l\",{\"children\":[\"HTTP and HTTPS versions are consolidated.\"]}],[\"$\",\"li\",\"b6n\",{\"children\":[\"www and non-www versions are consolidated.\"]}],[\"$\",\"li\",\"b6p\",{\"children\":[\"Uppercase and lowercase URL variants do not create duplicates.\"]}],[\"$\",\"li\",\"b6r\",{\"children\":[\"Filtered or sorted versions are indexable only when they should be.\"]}],[\"$\",\"li\",\"b6t\",{\"children\":[\"Client-side routing does not generate multiple paths for the same content.\"]}],[\"$\",\"li\",\"b6v\",{\"children\":[\"Canonical tags match sitemap URLs where appropriate.\"]}]]}]\n55:[\"$\",\"p\",\"b6x\",{\"children\":[\"In a SPA SEO audit, canonicals are not just another checkbox. They help stop your routing system from creating a duplicate-content mess.\"]}]\n56:[\"$\",\"h2\",\"b6z\",{\"id\":\"6-structured-data-and-entity-clarity\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"6. Structured Data and Entity Clarity\"]}]\n57:[\"$\",\"p\",\"b71\",{\"children\":[\"Structured data helps machines understand what a page is about. That matters for traditional search, rich results, and AI visibility.\"]}]\n58:[\"$\",\"p\",\"b73\",{\"children\":[\"Check:\"]}]\n59:[\"$\",\"ul\",\"b75-parent\",{\"children\":[[\"$\",\"li\",\"b75\",{\"children\":[\"JSON-LD schema is present in the initial HTML where possible.\"]}],[\"$\",\"li\",\"b77\",{\"children\":[\"Schema matches visible page content.\"]}],[\"$\",\"li\",\"b79\",{\"children\":[\"Product, Article, FAQ, Breadcrumb, Organization, LocalBusiness, SoftwareApplication, or Review schema is used only where appropriate.\"]}],[\"$\",\"li\",\"b7b\",{\"children\":[\"JavaScript does not inject schema too late or remove it during hydration.\"]}],[\"$\",\"li\",\"b7d\",{\"children\":[\"Schema is not duplicated across routes.\"]}],[\"$\",\"li\",\"b7f\",{\"children\":[\"Required and recommended fields are not empty.\"]}],[\"$\",\"li\",\"b7h\",{\"children\":[\"Entity names are consistent across page copy, schema, headings, and metadata.\"]}],[\"$\",\"li\",\"b7j\",{\"children\":[\"Breadcrumb schema matches visible breadcrumbs.\"]}],[\"$\",\"li\",\"b7l\",{\"children\":[\"FAQ schema, if used, matches visible FAQ content.\"]}],[\"$\",\"li\",\"b7n\",{\"children\":[\"Structured data is tested on both raw and rendered versions.\"]}]]}]\n5a:[\"$\",\"p\",\"b7p\",{\"children\":[\"Do not use schema as decoration. Use it to clarify what already exists on the page.\"]}]\n5b:[\"$\",\"h2\",\"b7r\",{\"id\":\"7-ai-crawlability-aeo-and-geo\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"7. AI Crawlability, AEO, and GEO\"]}]\n5c:[\"$\",\"p\",\"b7t\",{\"children\":[\"AI search adds another layer to crawlability. Traditional SEO already requires pages to be discoverable, renderable, and trustworthy.\"]}]\n5d:[\"$\",\"p\",\"b7w\",{\"children\":[\"AEO and GEO raise another question: \",[\"$\",\"strong\",\"s7v\",{\"children\":[\"can AI systems extract useful answers, entities, and citations from your site without fighting your front end?\"]}]]}]\n5e:[\"$\",\"p\",\"b7y\",{\"children\":[\"Check:\"]}]\n5f:[\"$\",\"ul\",\"b80-parent\",{\"children\":[[\"$\",\"li\",\"b80\",{\"children\":[\"Critical content is available in the initial HTML through SSR, SSG, or reliable pre-rendering.\"]}],[\"$\",\"li\",\"b82\",{\"children\":[\"Pages answer clear questions in plain language.\"]}],[\"$\",\"li\",\"b84\",{\"children\":[\"Important entities are named consistently.\"]}],[\"$\",\"li\",\"b86\",{\"children\":[\"Product, service, feature, audience, location, and pricing information is not hidden behind interactions.\"]}],[\"$\",\"li\",\"b88\",{\"children\":[\"FAQs are visible on-page, not only injected after user action.\"]}],[\"$\",\"li\",\"b8a\",{\"children\":[\"Internal links help crawlers understand topical relationships.\"]}],[\"$\",\"li\",\"b8c\",{\"children\":[\"Schema supports the visible "])</script><script>self.__next_f.push([1,"content.\"]}],[\"$\",\"li\",\"b8e\",{\"children\":[\"Pages are not blocked for non-Google crawlers unless intentional.\"]}],[\"$\",\"li\",\"b8g\",{\"children\":[\"robots.txt does not accidentally block resources required to understand the page.\"]}],[\"$\",\"li\",\"b8i\",{\"children\":[\"Key content can be extracted without clicking, scrolling forever, or running complex JavaScript.\"]}]]}]\n60:[\"$\",\"p\",\"b8k\",{\"children\":[\"Many SPA teams assume “Google can render JavaScript” means everyone can. That is not a safe assumption. For AI visibility, your safest content is content that is easy to fetch, parse, and understand.\"]}]\n61:[\"$\",\"h2\",\"b8m\",{\"id\":\"8-robots-txt-status-codes-and-crawl-access\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"8. robots.txt, Status Codes, and Crawl Access\"]}]\n62:[\"$\",\"p\",\"b8o\",{\"children\":[\"Before blaming rendering, make sure crawlers are allowed to access the site in the first place.\"]}]\n63:[\"$\",\"p\",\"b8q\",{\"children\":[\"Check:\"]}]\n64:[\"$\",\"ul\",\"b8s-parent\",{\"children\":[[\"$\",\"li\",\"b8s\",{\"children\":[\"robots.txt does not block important pages.\"]}],[\"$\",\"li\",\"b8u\",{\"children\":[\"robots.txt does not block CSS or JavaScript files needed for rendering.\"]}],[\"$\",\"li\",\"b8w\",{\"children\":[\"API endpoints needed to render public content are not blocked if crawlers depend on them.\"]}],[\"$\",\"li\",\"b8y\",{\"children\":[\"Important URLs return 200 status codes.\"]}],[\"$\",\"li\",\"b90\",{\"children\":[\"Redirect chains are cleaned up.\"]}],[\"$\",\"li\",\"b92\",{\"children\":[\"Broken routes do not return soft 404s with 200 status codes.\"]}],[\"$\",\"li\",\"b94\",{\"children\":[\"Real 404 pages return 404 status codes.\"]}],[\"$\",\"li\",\"b96\",{\"children\":[\"Protected or private app routes are not accidentally indexable.\"]}],[\"$\",\"li\",\"b98\",{\"children\":[\"Staging or preview environments are not indexed.\"]}],[\"$\",\"li\",\"b9c\",{\"children\":[\"Production pages are not carrying staging \",[\"$\",\"code\",\"s9a\",{\"children\":[\"noindex\"]}],\" rules.\"]}]]}]\n65:[\"$\",\"p\",\"b9e\",{\"children\":[\"JavaScript sites often blur the line between “the route exists in the app” and “the server returns a valid page.” Search engines care about both.\"]}]\n66:[\"$\",\"h2\",\"b9g\",{\"id\":\"9-core-web-vitals-and-performance\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"9. Core Web Vitals and Performance\"]}]\n67:[\"$\",\"p\",\"b9i\",{\"children\":[\"Performance is not just a Lighthouse score. It affects crawling, user experience, and conversion.\"]}]\n68:[\"$\",\"p\",\"b9k\",{\"children\":[\"Check:\"]}]\n69:[\"$\",\"ul\",\"b9m-parent\",{\"children\":[[\"$\",\"li\",\"b9m\",{\"children\":[\"JavaScript bundles are not excessively large.\"]}],[\"$\",\"li\",\"b9o\",{\"children\":[\"Unused JavaScript is reduced where possible.\"]}],[\"$\",\"li\",\"b9q\",{\"children\":[\"Main content is not delayed by heavy client-side rendering.\"]}],[\"$\",\"li\",\"b9s\",{\"children\":[\"Largest Contentful Paint is not slowed by app shell rendering.\"]}],[\"$\",\"li\",\"b9u\",{\"children\":[\"Interaction to Next Paint is not hurt by long JavaScript tasks.\"]}],[\"$\",\"li\",\"b9w\",{\"children\":[\"Third-party scripts are not blocking important rendering.\"]}],[\"$\",\"li\",\"b9y\",{\"children\":[\"Images are optimized and not dependent on late client-side loading.\"]}],[\"$\",\"li\",\"ba0\",{\"children\":[\"Fonts do not cause major layout shifts.\"]}],[\"$\",\"li\",\"ba2\",{\"children\":[\"Lazy loading does not hide important content from crawlers.\"]}],[\"$\",\"li\",\"ba4\",{\"children\":[\"Core Web Vitals are reviewed for priority templates, not just the homepage.\"]}]]}]\n6a:[\"$\",\"p\",\"ba6\",{\"children\":[\"A SPA can feel fast to your team and still be slow for SEO. If your JavaScript takes too long to deliver the message, the page loses twice: once in search and once in conversion.\"]}]\n6b:[\"$\",\"h2\",\"ba8\",{\"id\":\"10-ux-and-conversion-risks\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"10. UX and Conversion Risks\"]}]\n6c:[\"$\",\"p\",\"bac\",{\"children\":[\"A \",[\"$\",\"strong\",\"saa\",{\"children\":[\"SPA SEO audit\"]}],\" should not stop at indexability. If a page gets traffic but fails to convert, the business still loses.\"]}]\n6d:[\"$\",\"p\",\"bae\",{\"children\":[\"Check:\"]}]\n6e:[\"$\",\"ul\",\"bag-parent\",{\"children\":[[\"$\",\"li\",\"bag\",{\"children"])</script><script>self.__next_f.push([1,"\":[\"The main value proposition is visible without waiting for full app hydration.\"]}],[\"$\",\"li\",\"bai\",{\"children\":[\"Calls to action appear early and work reliably.\"]}],[\"$\",\"li\",\"bak\",{\"children\":[\"Forms do not break when JavaScript errors occur.\"]}],[\"$\",\"li\",\"bam\",{\"children\":[\"Pricing, demo, signup, or checkout paths are crawlable and usable.\"]}],[\"$\",\"li\",\"bao\",{\"children\":[\"Error states are clear and recoverable.\"]}],[\"$\",\"li\",\"baq\",{\"children\":[\"Page copy explains what the product or service does without relying on animations.\"]}],[\"$\",\"li\",\"bas\",{\"children\":[\"Navigation is understandable without app-specific behavior.\"]}],[\"$\",\"li\",\"bau\",{\"children\":[\"Mobile users can access the same core content.\"]}],[\"$\",\"li\",\"baw\",{\"children\":[\"Tracking scripts do not slow the page or interfere with rendering.\"]}],[\"$\",\"li\",\"bay\",{\"children\":[\"Conversion pages are not accidentally noindexed.\"]}]]}]\n6f:[\"$\",\"p\",\"bb0\",{\"children\":[\"The goal is not a green score. The goal is a page that can be found, understood, trusted, and acted on.\"]}]\n70:[\"$\",\"h2\",\"bb2\",{\"id\":\"11-framework-and-architecture-review\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"11. Framework and Architecture Review\"]}]\n71:[\"$\",\"p\",\"bb4\",{\"children\":[\"Different JavaScript setups create different SEO risks. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. But you need to know how each important page is being delivered.\"]}]\n72:[\"$\",\"p\",\"bb6\",{\"children\":[\"Check:\"]}]\n73:[\"$\",\"ul\",\"bb8-parent\",{\"children\":[[\"$\",\"li\",\"bb8\",{\"children\":[\"The rendering mode is known for each important template.\"]}],[\"$\",\"li\",\"bba\",{\"children\":[\"Server-side rendering, static generation, client-side rendering, or pre-rendering is documented.\"]}],[\"$\",\"li\",\"bbc\",{\"children\":[\"Developers and SEO teams agree which pages must be indexable.\"]}],[\"$\",\"li\",\"bbe\",{\"children\":[\"Public marketing pages are not treated like logged-in app screens.\"]}],[\"$\",\"li\",\"bbg\",{\"children\":[\"Framework upgrades are tested for rendering changes.\"]}],[\"$\",\"li\",\"bbi\",{\"children\":[\"Route-level metadata is tested after deployments.\"]}],[\"$\",\"li\",\"bbk\",{\"children\":[\"Build changes do not accidentally remove pre-rendered content.\"]}],[\"$\",\"li\",\"bbm\",{\"children\":[\"API failures do not produce thin indexable pages.\"]}],[\"$\",\"li\",\"bbo\",{\"children\":[\"Error boundaries do not hide content from crawlers.\"]}],[\"$\",\"li\",\"bbq\",{\"children\":[\"SEO checks are included before major releases.\"]}]]}]\n74:[\"$\",\"p\",\"bbt\",{\"children\":[\"The exact fix depends on the stack. The audit pattern stays the same: \",[\"$\",\"strong\",\"sbs\",{\"children\":[\"prove what crawlers get, then fix the gap.\"]}]]}]\n75:[\"$\",\"h2\",\"bbv\",{\"id\":\"12-google-search-console-checks\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"12. Google Search Console Checks\"]}]\n76:[\"$\",\"p\",\"bbx\",{\"children\":[\"Google Search Console will not tell you everything, but it will show useful symptoms.\"]}]\n77:[\"$\",\"p\",\"bbz\",{\"children\":[\"Check:\"]}]\n78:[\"$\",\"ul\",\"bc1-parent\",{\"children\":[[\"$\",\"li\",\"bc1\",{\"children\":[\"Important URLs are indexed.\"]}],[\"$\",\"li\",\"bc3\",{\"children\":[\"Important URLs are not stuck in “Discovered, currently not indexed” without explanation.\"]}],[\"$\",\"li\",\"bc7\",{\"children\":[\"Important URLs are not excluded by \",[\"$\",\"code\",\"sc5\",{\"children\":[\"noindex\"]}],\".\"]}],[\"$\",\"li\",\"bc9\",{\"children\":[\"Google’s selected canonical matches your intended canonical.\"]}],[\"$\",\"li\",\"bcb\",{\"children\":[\"Crawled pages show the expected content.\"]}],[\"$\",\"li\",\"bcd\",{\"children\":[\"Page indexing reports are reviewed by template type.\"]}],[\"$\",\"li\",\"bcf\",{\"children\":[\"Sitemap submissions match your indexable URL strategy.\"]}],[\"$\",\"li\",\"bch\",{\"children\":[\"Performance data is reviewed for pages that should drive revenue.\"]}],[\"$\",\"li\",\"bcj\",{\"children\":[\"Query data is checked for technical GEO, AEO, and crawlability demand.\"]}],[\"$\",\"li\",\"bcl\",{\"children\":[\"Drops are compared against deployments, migrations, and framework changes.\"]}]]}]\n79:[\"$\",\"p\",\"bcn\",{\"children\":[\"Treat Search Console as evidence, not a magic oracle. If impressio"])</script><script>self.__next_f.push([1,"ns are weak, pages are excluded, or Google chooses unexpected canonicals, your JavaScript delivery may be part of the problem.\"]}]\n7a:[\"$\",\"h2\",\"bcp\",{\"id\":\"13-log-file-and-bot-behavior-review\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"13. Log File and Bot Behavior Review\"]}]\n7b:[\"$\",\"p\",\"bcr\",{\"children\":[\"If you have log access, use it. Logs show what crawlers actually did.\"]}]\n7c:[\"$\",\"p\",\"bct\",{\"children\":[\"Check:\"]}]\n7d:[\"$\",\"ul\",\"bcv-parent\",{\"children\":[[\"$\",\"li\",\"bcv\",{\"children\":[\"Googlebot is crawling important URLs.\"]}],[\"$\",\"li\",\"bcx\",{\"children\":[\"Important sections are not being ignored.\"]}],[\"$\",\"li\",\"bcz\",{\"children\":[\"Crawl frequency changed after a migration or release.\"]}],[\"$\",\"li\",\"bd1\",{\"children\":[\"Bots are hitting redirected or broken routes too often.\"]}],[\"$\",\"li\",\"bd3\",{\"children\":[\"Server responses for crawlers are clean and consistent.\"]}],[\"$\",\"li\",\"bd5\",{\"children\":[\"Static assets needed for rendering are accessible.\"]}],[\"$\",\"li\",\"bd7\",{\"children\":[\"Non-Google crawlers are not accidentally blocked if AI visibility matters.\"]}],[\"$\",\"li\",\"bd9\",{\"children\":[\"Crawl waste is reduced on low-value routes.\"]}],[\"$\",\"li\",\"bdb\",{\"children\":[\"Money pages receive crawl attention.\"]}],[\"$\",\"li\",\"bdd\",{\"children\":[\"Bot behavior aligns with your sitemap and internal linking strategy.\"]}]]}]\n7e:[\"$\",\"p\",\"bdf\",{\"children\":[\"Logs are useful because they show reality: not what the crawler could do, not what the framework should do, but what actually happened.\"]}]\n7f:[\"$\",\"h2\",\"bdh\",{\"id\":\"14-copy-and-content-extraction\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"14. Copy and Content Extraction\"]}]\n80:[\"$\",\"p\",\"bdj\",{\"children\":[\"JavaScript SEO is not only technical. Once crawlers reach the page, they still need meaningful content.\"]}]\n81:[\"$\",\"p\",\"bdl\",{\"children\":[\"Check:\"]}]\n82:[\"$\",\"ul\",\"bdn-parent\",{\"children\":[[\"$\",\"li\",\"bdn\",{\"children\":[\"The page clearly states what the company, product, or service does.\"]}],[\"$\",\"li\",\"bdp\",{\"children\":[\"The target audience is obvious.\"]}],[\"$\",\"li\",\"bdr\",{\"children\":[\"The problem, solution, and outcome are explained.\"]}],[\"$\",\"li\",\"bdt\",{\"children\":[\"Important terms are written naturally in visible copy.\"]}],[\"$\",\"li\",\"bdv\",{\"children\":[\"Headings describe the page, not just marketing slogans.\"]}],[\"$\",\"li\",\"bdx\",{\"children\":[\"Feature descriptions are not hidden inside components that require JavaScript to populate.\"]}],[\"$\",\"li\",\"bdz\",{\"children\":[\"FAQs answer real buyer or technical questions.\"]}],[\"$\",\"li\",\"be1\",{\"children\":[\"Comparison and alternative pages include enough context to be useful.\"]}],[\"$\",\"li\",\"be3\",{\"children\":[\"Thin pages are improved or removed from indexation.\"]}],[\"$\",\"li\",\"be5\",{\"children\":[\"AI extraction would produce an accurate summary of the page.\"]}]]}]\n83:[\"$\",\"p\",\"be7\",{\"children\":[\"Crawlability gets the page seen. Good copy gets the page understood. Clear conversion paths get the buyer moving. You need all three.\"]}]\n84:[\"$\",\"h2\",\"be9\",{\"id\":\"15-ci-and-release-monitoring\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"15. CI and Release Monitoring\"]}]\n85:[\"$\",\"p\",\"beb\",{\"children\":[\"A one-time audit helps. A repeatable process protects you from regressions.\"]}]\n86:[\"$\",\"p\",\"bed\",{\"children\":[\"Check:\"]}]\n87:[\"$\",\"ul\",\"bef-parent\",{\"children\":[[\"$\",\"li\",\"bef\",{\"children\":[\"Priority URLs are tested before major releases.\"]}],[\"$\",\"li\",\"beh\",{\"children\":[\"Raw HTML snapshots are compared over time.\"]}],[\"$\",\"li\",\"bej\",{\"children\":[\"Rendered HTML snapshots are compared over time.\"]}],[\"$\",\"li\",\"bel\",{\"children\":[\"Metadata changes are monitored.\"]}],[\"$\",\"li\",\"ben\",{\"children\":[\"Canonical changes are monitored.\"]}],[\"$\",\"li\",\"bep\",{\"children\":[\"Robots directives are monitored.\"]}],[\"$\",\"li\",\"ber\",{\"children\":[\"Schema presence is tested.\"]}],[\"$\",\"li\",\"bet\",{\"children\":[\"Internal links are crawled after deployments.\"]}],[\"$\",\"li\",\"bev\",{\"children\":[\"Performance regressions are flagged.\"]}],[\"$\",\"li\",\"bex\",{\"children\":[\"SEO-critical templates have QA requirements.\"]}]]}]\n88:[\"$\",\"p\",\"b"])</script><script>self.__next_f.push([1,"ez\",{\"children\":[\"JavaScript SEO problems often appear after innocent changes: a route refactor, framework upgrade, hydration fix, analytics script, redesign, CMS change, or deployment config update. None of those sound like SEO projects. They can still break SEO.\"]}]\n89:[\"$\",\"h2\",\"bf1\",{\"id\":\"how-savage-audit-fits-naturally\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"How Savage Audit Fits Naturally\"]}]\n8a:[\"$\",\"p\",\"bf3\",{\"children\":[\"Savage Audit is built for exactly this kind of problem.\"]}]\n8b:[\"$\",\"p\",\"bf5\",{\"children\":[\"JavaScript-heavy websites usually sit between three teams:\"]}]\n8c:[\"$\",\"ul\",\"bf7-parent\",{\"children\":[[\"$\",\"li\",\"bf7\",{\"children\":[\"Developers care about architecture, deployment, performance, and maintainability.\"]}],[\"$\",\"li\",\"bf9\",{\"children\":[\"SEO teams care about crawlability, indexation, rankings, and structured data.\"]}],[\"$\",\"li\",\"bfb\",{\"children\":[\"Founders and marketers care about pipeline, demos, signups, and revenue.\"]}]]}]\n8d:[\"$\",\"p\",\"bfd\",{\"children\":[\"Everyone can be right and the site can still be broken.\"]}]\n8e:[\"$\",\"p\",\"bff\",{\"children\":[\"Savage Audit helps identify JavaScript crawlability problems, single page application SEO issues, raw HTML vs rendered HTML gaps, metadata and canonical failures, AI crawlability risks, technical SEO blockers, UX problems, copy gaps, and prioritized fixes your dev team can actually use.\"]}]\n8f:[\"$\",\"p\",\"bfn\",{\"children\":[\"For related technical checks, see the \",\"Technical GEO Audit Checklist\",\", the \",\"Website Audit Tool for Developers\",\", and the guide to \",\"LLMs.txt vs Robots.txt vs Structured Data\",\".\"]}]\n90:[\"$\",\"p\",\"bfp\",{\"children\":[\"The point is not to shame the stack. React, Vue, Angular, Next.js, Nuxt, Backbone.js, and custom SPAs can all work. The point is to stop pretending the browser experience is the same as crawler access.\"]}]\n91:[\"$\",\"h2\",\"bfr\",{\"id\":\"final-takeaway\",\"className\":\"portable-heading portable-heading-h2\",\"children\":[\"Final Takeaway\"]}]\n92:[\"$\",\"p\",\"bft\",{\"children\":[\"Your single page application can look beautiful in the browser and still be a search liability.\"]}]\n93:[\"$\",\"p\",\"bfv\",{\"children\":[\"Do not start with vanity metrics. Do not start by rewriting every headline. Do not assume “Google can render JavaScript” means your crawlability is fine.\"]}]\n94:[\"$\",\"p\",\"bfx\",{\"children\":[\"Start with proof.\"]}]\n95:[\"$\",\"p\",\"bfz\",{\"children\":[\"Compare raw HTML against rendered HTML. Check internal links. Verify metadata. Test schema. Review robots directives. Look at crawl access. Then check whether AI crawlers can extract the same core content your users see.\"]}]\n96:[\"$\",\"p\",\"bg1\",{\"children\":[\"If bots cannot read your app, buyers may never find it. That is the real JavaScript SEO audit.\"]}]\n"])</script><script>self.__next_f.push([1,"97:[\"$\",\"section\",null,{\"className\":\"blog-faqs\",\"aria-labelledby\":\"blog-faqs\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-faqs-copy\",\"children\":[[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"FAQ\"}],[\"$\",\"h2\",null,{\"id\":\"blog-faqs\",\"children\":\"Common questions\"}]]}],[\"$\",\"div\",null,{\"className\":\"blog-faq-list\",\"children\":[[\"$\",\"article\",\"What is a JavaScript SEO audit?\",{\"className\":\"blog-faq-item\",\"children\":[[\"$\",\"h3\",null,{\"children\":\"What is a JavaScript SEO audit?\"}],[[\"$\",\"p\",\"iYsNT5uw0udeBNFcbCKMIy\",{\"children\":[\"A JavaScript SEO audit checks whether a JavaScript-heavy website can be discovered, rendered, indexed, understood, and ranked by search engines. It compares raw HTML, rendered HTML, metadata, internal links, schema, status codes, performance, and crawl access.\"]}]]]}],[\"$\",\"article\",\"What is an AI crawlability audit checklist?\",{\"className\":\"blog-faq-item\",\"children\":[[\"$\",\"h3\",null,{\"children\":\"What is an AI crawlability audit checklist?\"}],[[\"$\",\"p\",\"iYsNT5uw0udeBNFcbCKMX6\",{\"children\":[\"An AI crawlability audit checklist verifies whether AI crawlers and answer engines can extract useful content from your site. It focuses on raw HTML access, clear copy, structured data, crawl permissions, internal links, and whether important content requires complex JavaScript execution.\"]}]]]}],[\"$\",\"article\",\"How do I check Backbone.js crawlability?\",{\"className\":\"blog-faq-item\",\"children\":[[\"$\",\"h3\",null,{\"children\":\"How do I check Backbone.js crawlability?\"}],[[\"$\",\"p\",\"iYsNT5uw0udeBNFcbCKMlE\",{\"children\":[\"For Backbone.js crawlability, start with routing and raw HTML. Check whether important URLs return meaningful content on direct server requests, whether internal links use crawlable anchors, and whether metadata is available before client-side DOM manipulation.\"]}]]]}],[\"$\",\"article\",\"When should I run a SPA SEO audit?\",{\"className\":\"blog-faq-item\",\"children\":[[\"$\",\"h3\",null,{\"children\":\"When should I run a SPA SEO audit?\"}],[[\"$\",\"p\",\"iYsNT5uw0udeBNFcbCKMzM\",{\"children\":[\"Run a SPA SEO audit before launches, migrations, redesigns, framework upgrades, and major routing changes. Also run one after unexplained organic traffic drops, indexation problems, canonical issues, or performance regressions.\"]}]]]}],[\"$\",\"article\",\"Why is my SPA indexed but not ranking well?\",{\"className\":\"blog-faq-item\",\"children\":[[\"$\",\"h3\",null,{\"children\":\"Why is my SPA indexed but not ranking well?\"}],[[\"$\",\"p\",\"iYsNT5uw0udeBNFcbCKNDU\",{\"children\":[\"An SPA can be indexed but still rank poorly if crawlers see thin raw HTML, delayed content, weak internal links, slow rendering, inconsistent metadata, or confusing canonicals. Indexing does not prove search engines fully understood the page.\"]}]]]}]]}]]}]\n"])</script><script>self.__next_f.push([1,"98:[\"$\",\"section\",null,{\"className\":\"blog-curated-links\",\"aria-labelledby\":\"curated-related-links\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-section-heading\",\"children\":[[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"Next audit steps\"}],[\"$\",\"h2\",null,{\"id\":\"curated-related-links\",\"children\":\"Keep the diagnosis moving\"}]]}],[\"$\",\"div\",null,{\"className\":\"blog-related-grid\",\"children\":[[\"$\",\"$L4\",\"/blog/technical-geo-audit-checklist-Technical GEO Audit Checklist\",{\"className\":\"blog-related-card blog-related-card--curated\",\"href\":\"/blog/technical-geo-audit-checklist\",\"title\":\"Technical GEO Audit Checklist\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"SavageAudit path\"}],[\"$\",\"strong\",null,{\"children\":\"Technical GEO Audit Checklist\"}],[\"$\",\"small\",null,{\"children\":\"Check crawlability, structured data, entity clarity, and citation readiness for AI search.\"}]]}],[\"$\",\"$L4\",\"/blog/website-audit-tool-for-developers-Website Audit Tool for Developers\",{\"className\":\"blog-related-card blog-related-card--curated\",\"href\":\"/blog/website-audit-tool-for-developers\",\"title\":\"Website Audit Tool for Developers\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"SavageAudit path\"}],[\"$\",\"strong\",null,{\"children\":\"Website Audit Tool for Developers\"}],[\"$\",\"small\",null,{\"children\":\"Review technical SEO, UX, copy, trust, conversion, and AI visibility before launch.\"}]]}],[\"$\",\"$L4\",\"/blog/llms-txt-vs-robots-txt-vs-structured-data-LLMs.txt vs Robots.txt vs Structured Data\",{\"className\":\"blog-related-card blog-related-card--curated\",\"href\":\"/blog/llms-txt-vs-robots-txt-vs-structured-data\",\"title\":\"LLMs.txt vs Robots.txt vs Structured Data\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"SavageAudit path\"}],[\"$\",\"strong\",null,{\"children\":\"LLMs.txt vs Robots.txt vs Structured Data\"}],[\"$\",\"small\",null,{\"children\":\"Understand which technical signals actually help AI discovery.\"}]]}]]}]]}]\n"])</script><script>self.__next_f.push([1,"99:[\"$\",\"section\",null,{\"className\":\"blog-related-reads\",\"aria-labelledby\":\"related-reads\",\"children\":[[\"$\",\"div\",null,{\"className\":\"blog-section-heading\",\"children\":[[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"Related reads\"}],[\"$\",\"h2\",null,{\"id\":\"related-reads\",\"children\":\"Keep auditing the outside view\"}]]}],[\"$\",\"div\",null,{\"className\":\"blog-related-grid\",\"children\":[[[\"$\",\"$L4\",\"website-audit-tool-for-developers\",{\"className\":\"blog-related-card\",\"href\":\"/blog/website-audit-tool-for-developers\",\"title\":\"Website Audit Tool for Developers: What to Check Before You Ship\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Technical Teardowns\"}],[\"$\",\"strong\",null,{\"children\":\"Website Audit Tool for Developers: What to Check Before You Ship\"}],[\"$\",\"small\",null,{\"children\":[13,\" min read\",\" by SavageAudit Team\"]}]]}],[\"$\",\"$L4\",\"technical-geo-audit-checklist\",{\"className\":\"blog-related-card\",\"href\":\"/blog/technical-geo-audit-checklist\",\"title\":\"Technical GEO Audit Checklist: Crawlability, Structured Data, and AI Citation Readiness\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Technical Teardowns\"}],[\"$\",\"strong\",null,{\"children\":\"Technical GEO Audit Checklist: Crawlability, Structured Data, and AI Citation Readiness\"}],[\"$\",\"small\",null,{\"children\":[13,\" min read\",\" by SavageAudit Team\"]}]]}],[\"$\",\"$L4\",\"website-speed-ux-seo-audit-tool\",{\"className\":\"blog-related-card\",\"href\":\"/blog/website-speed-ux-seo-audit-tool\",\"title\":\"Speed, UX, and SEO Audit Tool: How to Review All Three Together\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"Product Updates\"}],[\"$\",\"strong\",null,{\"children\":\"Speed, UX, and SEO Audit Tool: How to Review All Three Together\"}],[\"$\",\"small\",null,{\"children\":[12,\" min read\",\" by SavageAudit Team\"]}]]}]],[\"$\",\"$L4\",null,{\"className\":\"blog-related-card blog-related-card--static\",\"href\":\"/blog\",\"title\":\"Browse all SavageAudit articles\",\"children\":[[\"$\",\"span\",null,{\"className\":\"mono\",\"children\":\"More research\"}],[\"$\",\"strong\",null,{\"children\":\"Browse the full SavageAudit blog\"}],[\"$\",\"small\",null,{\"children\":\"SEO, AI visibility, UX, proof, and conversion teardown notes.\"}]]}]]}]]}]\n"])</script><script>self.__next_f.push([1,"9a:[\"$\",\"section\",null,{\"className\":\"blog-article-cta\",\"aria-labelledby\":\"article-cta\",\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"span\",null,{\"className\":\"badge\",\"children\":\"SavageAudit\"}],[\"$\",\"h2\",null,{\"id\":\"article-cta\",\"children\":\"Run your own public presence audit\"}],[\"$\",\"p\",null,{\"children\":\"See how your website, search footprint, AI visibility, social proof, and conversion trust look from the outside.\"}]]}],[\"$\",\"div\",null,{\"className\":\"blog-article-cta-actions\",\"children\":[[\"$\",\"$L4\",null,{\"className\":\"primary\",\"href\":\"/#home-roast-input\",\"title\":\"Roast My Site\",\"children\":\"Roast My Site\"}],[\"$\",\"$L4\",null,{\"className\":\"secondary\",\"href\":\"/pricing\",\"title\":\"View pricing\",\"children\":\"View pricing\"}],[\"$\",\"$L4\",null,{\"className\":\"secondary\",\"href\":\"/compare\",\"title\":\"Compare websites\",\"children\":\"Compare sites\"}]]}]]}]\n9b:[\"$\",\"footer\",null,{\"className\":\"blog-article-footer\",\"children\":[[\"$\",\"$L4\",null,{\"href\":\"/blog\",\"className\":\"mono blog-back-link\",\"title\":\"Go to SavageAudit blog\",\"children\":\"Back to blog\"}],[\"$\",\"$L20\",null,{\"title\":\"JavaScript SEO Audit Checklist for SPAs: Make Sure Crawlers Can Actually Read Your Site\",\"url\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\"}]]}]\n1a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n18:null\n"])</script><script>self.__next_f.push([1,"1c:[[\"$\",\"title\",\"0\",{\"children\":\"JavaScript SEO Audit Checklist for SPAs | SavageAudit\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Audit SPA crawlability, rendering, metadata, AI visibility, UX, and conversion risks before your JavaScript site loses search visibility.\"}],[\"$\",\"meta\",\"2\",{\"name\":\"application-name\",\"content\":\"SavageAudit\"}],[\"$\",\"link\",\"3\",{\"rel\":\"author\",\"href\":\"https://savageaudit.com\"}],[\"$\",\"meta\",\"4\",{\"name\":\"author\",\"content\":\"SavageAudit Team\"}],[\"$\",\"link\",\"5\",{\"rel\":\"manifest\",\"href\":\"/site.webmanifest\",\"crossOrigin\":\"$undefined\"}],[\"$\",\"meta\",\"6\",{\"name\":\"keywords\",\"content\":\"website audit,SEO audit,AI website audit,performance audit,conversion audit,UX audit,SavageAudit,javascript seo audit,single page application seo,crawlability audit,javascript crawlability,technical seo crawlability,spa seo audit,ai crawlability audit,Technical Teardowns,Technical SEO \u0026 Website Audits\"}],[\"$\",\"meta\",\"7\",{\"name\":\"creator\",\"content\":\"SavageAudit\"}],[\"$\",\"meta\",\"8\",{\"name\":\"publisher\",\"content\":\"SavageAudit\"}],[\"$\",\"meta\",\"9\",{\"name\":\"robots\",\"content\":\"index, follow\"}],[\"$\",\"meta\",\"10\",{\"name\":\"googlebot\",\"content\":\"index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1\"}],[\"$\",\"meta\",\"11\",{\"name\":\"article:published_time\",\"content\":\"2026-07-17T12:00:00Z\"}],[\"$\",\"meta\",\"12\",{\"name\":\"article:modified_time\",\"content\":\"2026-07-17T12:00:00Z\"}],[\"$\",\"meta\",\"13\",{\"name\":\"article:author\",\"content\":\"SavageAudit Team\"}],[\"$\",\"meta\",\"14\",{\"name\":\"article:section\",\"content\":\"Technical Teardowns\"}],[\"$\",\"link\",\"15\",{\"rel\":\"canonical\",\"href\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\"}],[\"$\",\"meta\",\"16\",{\"name\":\"mobile-web-app-capable\",\"content\":\"yes\"}],[\"$\",\"meta\",\"17\",{\"name\":\"apple-mobile-web-app-title\",\"content\":\"SavageAudit\"}],[\"$\",\"meta\",\"18\",{\"name\":\"apple-mobile-web-app-status-bar-style\",\"content\":\"default\"}],[\"$\",\"meta\",\"19\",{\"property\":\"og:title\",\"content\":\"JavaScript SEO Audit Checklist for SPAs\"}],[\"$\",\"meta\",\"20\",{\"property\":\"og:description\",\"content\":\"Check whether crawlers, AI systems, and users can actually read your JavaScript-heavy website before search visibility suffers.\"}],[\"$\",\"meta\",\"21\",{\"property\":\"og:url\",\"content\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps\"}],[\"$\",\"meta\",\"22\",{\"property\":\"og:site_name\",\"content\":\"SavageAudit\"}],[\"$\",\"meta\",\"23\",{\"property\":\"og:image\",\"content\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps/opengraph-image\"}],[\"$\",\"meta\",\"24\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"25\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"26\",{\"property\":\"og:image:alt\",\"content\":\"Dark abstract website audit dashboard showing JavaScript crawlability checks and orange warning panels.\"}],[\"$\",\"meta\",\"27\",{\"property\":\"og:type\",\"content\":\"article\"}],[\"$\",\"meta\",\"28\",{\"property\":\"article:published_time\",\"content\":\"2026-07-17T12:00:00Z\"}],[\"$\",\"meta\",\"29\",{\"property\":\"article:modified_time\",\"content\":\"2026-07-17T12:00:00Z\"}],[\"$\",\"meta\",\"30\",{\"property\":\"article:author\",\"content\":\"SavageAudit Team\"}],[\"$\",\"meta\",\"31\",{\"property\":\"article:section\",\"content\":\"Technical Teardowns\"}],[\"$\",\"meta\",\"32\",{\"property\":\"article:tag\",\"content\":\"javascript seo audit\"}],[\"$\",\"meta\",\"33\",{\"property\":\"article:tag\",\"content\":\"single page application seo\"}],[\"$\",\"meta\",\"34\",{\"property\":\"article:tag\",\"content\":\"crawlability audit\"}],[\"$\",\"meta\",\"35\",{\"property\":\"article:tag\",\"content\":\"javascript crawlability\"}],[\"$\",\"meta\",\"36\",{\"property\":\"article:tag\",\"content\":\"technical seo crawlability\"}],[\"$\",\"meta\",\"37\",{\"property\":\"article:tag\",\"content\":\"spa seo audit\"}],[\"$\",\"meta\",\"38\",{\"property\":\"article:tag\",\"content\":\"ai crawlability audit\"}],[\"$\",\"meta\",\"39\",{\"property\":\"article:tag\",\"content\":\"Technical Teardowns\"}],[\"$\",\"meta\",\"40\",{\"property\":\"article:tag\",\"content\":\"Technical SEO \u0026 Website Audits\"}],[\"$\",\"meta\",\"41\",{\"property\":\"article:tag\",\"content\":\"SavageAudit\"}],[\"$\",\"meta\",\"42\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],\"$L9c\",\"$L9d\",\"$L9e\",\"$L9f\",\"$La0\",\"$La1\",\"$La2\",\"$La3\",\"$La4\",\"$La5\",\"$La6\",\"$La7\"]\n"])</script><script>self.__next_f.push([1,"9c:[\"$\",\"meta\",\"43\",{\"name\":\"twitter:site\",\"content\":\"@savageaudit\"}]\n9d:[\"$\",\"meta\",\"44\",{\"name\":\"twitter:creator\",\"content\":\"@savageaudit\"}]\n9e:[\"$\",\"meta\",\"45\",{\"name\":\"twitter:title\",\"content\":\"JavaScript SEO Audit Checklist for SPAs | SavageAudit\"}]\n9f:[\"$\",\"meta\",\"46\",{\"name\":\"twitter:description\",\"content\":\"Audit SPA crawlability, rendering, metadata, AI visibility, UX, and conversion risks before your JavaScript site loses search visibility.\"}]\na0:[\"$\",\"meta\",\"47\",{\"name\":\"twitter:image\",\"content\":\"https://savageaudit.com/blog/javascript-seo-audit-checklist-single-page-apps/opengraph-image\"}]\na1:[\"$\",\"link\",\"48\",{\"rel\":\"shortcut icon\",\"href\":\"/favicon.ico\"}]\na2:[\"$\",\"link\",\"49\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.321bb643.ico\",\"sizes\":\"64x64\",\"type\":\"image/x-icon\"}]\na3:[\"$\",\"link\",\"50\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\"}]\na4:[\"$\",\"link\",\"51\",{\"rel\":\"icon\",\"href\":\"/favicon-96x96.png\",\"sizes\":\"96x96\",\"type\":\"image/png\"}]\na5:[\"$\",\"link\",\"52\",{\"rel\":\"icon\",\"href\":\"/icon.png\",\"sizes\":\"512x512\",\"type\":\"image/png\"}]\na6:[\"$\",\"link\",\"53\",{\"rel\":\"apple-touch-icon\",\"href\":\"/apple-touch-icon.png\",\"sizes\":\"180x180\",\"type\":\"image/png\"}]\na7:[\"$\",\"$La8\",\"54\",{}]\n"])</script></body></html>