How to test the content is LLM process friendly

Test how AI models read your website. Learn quick methods and use the LLM Content Analyzer tool to improve SEO, readability, and AI discoverability.

Introduction

AI models read websites differently than humans—they ignore visual design and focus on structured text in the HTML source. Content that looks great visually may be invisible to AI if it's embedded in images, loaded via JavaScript, or lacks semantic structure.

Outlining a testing approach helps you identify and fix issues that prevent AI models from properly understanding your content, improving both AI discoverability and SEO performance.

⚠️ Important Note: This guide is for educational purposes only. The LLM landscape is rapidly evolving and entirely new territory. AI model behaviors, crawling patterns, and optimization strategies may change significantly as the technology develops. Use these techniques as learning tools while staying updated on emerging best practices.

Quick Testing Methods

Step 1 — View Raw HTML Text

  1. Open your Webflow site in Chrome (or any modern browser).

  2. Right-click → View Page Source (or press Ctrl+U / Cmd+Option+U).

  3. In the source code, look for your actual content text.

    • Good sign: You see your headings (<h1>, <h2>), paragraphs (<p>), and list items (<li>) clearly as plain text.

    • Bad sign: You see gibberish, JavaScript code, or <canvas> elements instead of readable words.

Step 2 — Simulate a “Plain Text” Read

  1. Open the browser Developer Tools (F12 or Ctrl+Shift+I / Cmd+Option+I).

  2. Go to the Console tab.

  3. Paste this JavaScript snippet:

    document.body.innerText
  4. Press Enter — the browser will dump only the readable text from the page.

    • This is very close to what I see when I fetch a webpage.

    • If critical info is missing here, I won’t see it either.

Step 3 — Check for Token Hostility

When looking at the text output:

  • Token-friendly:

    • Normal spacing

    • Regular punctuation

    • No excessive symbols

    • No weird encodings

  • Token-hostile:

    • Text is inside images or icons

    • Special Unicode characters instead of normal ones

    • Overloaded with emojis, symbols, or decorative glyphs

Step 4 — Quick Keyword Scan

Search in the output (Ctrl+F) for your target keywords.

  • If they appear clean and intact, LLMs can match them easily.

  • If they’re broken across weird symbols or missing entirely, that’s a ranking problem.

    Advanced Testing Tool

    Would you like to see what LLM sees? Try out the following

    The following will give you an instant grades any webpage A-F on how easily AI models like ChatGPT and Claude can read and understand its content, plus gives specific fixes to improve AI-friendliness.

    Instructions

    • Open the webpage in browser.

    • Open the Devtool with website (use CTRL+shift+I).

    • Go to console section.

    • Paste the following code at console (if see a warning then first type allow pasting at console)

      Warning: Don’t paste code into the DevTools Console that you don’t understand or haven’t reviewed yourself. This could allow attackers to steal your identity or take control of your computer. Please type ‘allow pasting’ below and press Enter to allow pasting.)


      LLM Content Analyzer Code

    (async () => {
      // Extract visible page text
      const visibleText = document.body.innerText.replace(/\s+/g, ' ').trim();
      
      // LLM Friendliness Analyzer
      function analyzeLLMFriendliness() {
        const scores = {};
        let totalScore = 0;
        
        // 1. Text Extraction Quality (25 points)
        const sourceHTML = document.documentElement.outerHTML;
        const textInSource = sourceHTML.includes(visibleText.slice(0, 100));
        const hasImages = document.querySelectorAll('img').length;
        const imagesWithAlt = document.querySelectorAll('img[alt]').length;
        const altCoverage = hasImages > 0 ? (imagesWithAlt / hasImages) * 100 : 100;
        
        scores.textExtraction = textInSource ? 25 : 10;
        totalScore += scores.textExtraction;
        
        // 2. Semantic HTML Structure (25 points)
        const h1Count = document.querySelectorAll('h1').length;
        const hasHeadings = document.querySelectorAll('h1, h2, h3, h4, h5, h6').length > 0;
        const hasParagraphs = document.querySelectorAll('p').length > 0;
        const hasLists = document.querySelectorAll('ul, ol').length > 0;
        
        let semanticScore = 0;
        if (h1Count === 1) semanticScore += 8;
        else if (h1Count > 1) semanticScore += 3;
        if (hasHeadings) semanticScore += 7;
        if (hasParagraphs) semanticScore += 5;
        if (hasLists) semanticScore += 5;
        
        scores.semantic = Math.min(semanticScore, 25);
        totalScore += scores.semantic;
        
        // 3. Content Visibility (15 points)
        const hiddenElements = document.querySelectorAll('[style*="display: none"], [style*="visibility: hidden"], .hidden').length;
        const totalElements = document.querySelectorAll('*').length;
        const visibilityRatio = 1 - (hiddenElements / totalElements);
        
        scores.visibility = Math.round(visibilityRatio * 15);
        totalScore += scores.visibility;
        
        // 4. Token Efficiency (15 points)
        const tokenCount = Math.ceil(visibleText.length / 4); // Rough estimate
        const efficiency = Math.min(visibleText.length / tokenCount, 5) / 5; // Characters per token
        
        scores.efficiency = Math.round(efficiency * 15);
        totalScore += scores.efficiency;
        
        // 5. Context Clarity (10 points)
        const title = document.title || '';
        const metaDesc = document.querySelector('meta[name="description"]')?.content || '';
        const hasTitle = title.length > 0;
        const hasMetaDesc = metaDesc.length > 0;
        
        scores.context = (hasTitle ? 5 : 0) + (hasMetaDesc ? 5 : 0);
        totalScore += scores.context;
        
        // 6. Accessibility (10 points)
        const linksWithText = document.querySelectorAll('a').length;
        const descriptiveLinks = Array.from(document.querySelectorAll('a')).filter(
          link => link.textContent && !['click here', 'read more', 'link'].includes(link.textContent.toLowerCase().trim())
        ).length;
        const linkScore = linksWithText > 0 ? (descriptiveLinks / linksWithText) * 10 : 10;
        
        scores.accessibility = Math.round(Math.min(linkScore + (altCoverage / 10), 10));
        totalScore += scores.accessibility;
        
        // Calculate grade
        let grade = 'F';
        if (totalScore >= 90) grade = 'A';
        else if (totalScore >= 80) grade = 'B';
        else if (totalScore >= 70) grade = 'C';
        else if (totalScore >= 60) grade = 'D';
        
        return { scores, totalScore, grade, altCoverage, tokenCount };
      }
      
      const analysis = analyzeLLMFriendliness();
      
      // Create enhanced popup UI
      const popup = document.createElement('div');
      popup.className = 'token-analyzer-popup';
      
      // Inject styles
      const styles = `
        <style>
          .token-analyzer-popup {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 560px;
            max-height: 90vh;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 16px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.15);
            z-index: 999999;
            overflow: hidden;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            animation: slideIn 0.3s ease-out;
          }
          
          @keyframes slideIn {
            from { transform: translateX(100%); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
          }
          
          .token-header {
            background: rgba(255,255,255,0.1);
            backdrop-filter: blur(10px);
            padding: 20px 24px;
            border-bottom: 1px solid rgba(255,255,255,0.2);
            color: white;
          }
          
          .token-title {
            font-size: 20px;
            font-weight: 600;
            margin: 0;
            display: flex;
            align-items: center;
            gap: 10px;
          }
          
          .token-icon {
            width: 24px;
            height: 24px;
            background: rgba(255,255,255,0.2);
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
          }
          
          .grade-badge {
            margin-left: auto;
            padding: 8px 16px;
            border-radius: 20px;
            font-weight: 700;
            font-size: 16px;
          }
          
          .grade-A { background: #28a745; }
          .grade-B { background: #17a2b8; }
          .grade-C { background: #ffc107; color: #000; }
          .grade-D { background: #fd7e14; }
          .grade-F { background: #dc3545; }
          
          .token-content {
            background: white;
            max-height: calc(90vh - 80px);
            overflow-y: auto;
          }
          
          .token-section {
            padding: 20px 24px;
            border-bottom: 1px solid #f0f0f0;
          }
          
          .token-section:last-child {
            border-bottom: none;
          }
          
          .section-title {
            font-size: 14px;
            font-weight: 600;
            color: #666;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            margin-bottom: 12px;
          }
          
          .text-preview {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 8px;
            padding: 16px;
            font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
            font-size: 12px;
            line-height: 1.5;
            color: #495057;
            max-height: 150px;
            overflow-y: auto;
            white-space: pre-wrap;
          }
          
          .stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            gap: 12px;
            margin-bottom: 16px;
          }
          
          .stat-card {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 8px;
            padding: 12px;
            text-align: center;
          }
          
          .stat-value {
            font-size: 20px;
            font-weight: 700;
            color: #495057;
            margin-bottom: 4px;
          }
          
          .stat-label {
            font-size: 11px;
            color: #6c757d;
            text-transform: uppercase;
            letter-spacing: 0.5px;
          }
          
          .llm-scores {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
            margin-bottom: 16px;
          }
          
          .score-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 12px;
            background: #f8f9fa;
            border-radius: 6px;
            font-size: 12px;
          }
          
          .score-value {
            font-weight: 600;
            color: #495057;
          }
          
          .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 10px 16px;
            border-radius: 8px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
            margin-right: 8px;
            margin-bottom: 8px;
          }
          
          .btn:hover {
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
          }
          
          .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
          }
          
          .btn-secondary {
            background: #6c757d;
          }
          
          .btn-danger {
            background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
          }
          
          .token-output {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 8px;
            padding: 16px;
            font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
            font-size: 11px;
            line-height: 1.4;
            max-height: 300px;
            overflow-y: auto;
            white-space: pre-wrap;
            color: #495057;
            margin-top: 12px;
          }
          
          .loading {
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 40px;
            color: #6c757d;
          }
          
          .spinner {
            width: 20px;
            height: 20px;
            border: 2px solid #e9ecef;
            border-top: 2px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-right: 8px;
          }
          
          @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
          }
          
          .tabs {
            display: flex;
            border-bottom: 1px solid #e9ecef;
          }
          
          .tab {
            padding: 12px 20px;
            cursor: pointer;
            border-bottom: 2px solid transparent;
            font-size: 14px;
            font-weight: 500;
            color: #666;
            transition: all 0.2s ease;
          }
          
          .tab.active {
            color: #667eea;
            border-bottom-color: #667eea;
          }
          
          .tab-content {
            display: none;
          }
          
          .tab-content.active {
            display: block;
          }
        </style>
      `;
      
      popup.innerHTML = styles + `
        <div class="token-header">
          <h3 class="token-title">
            <div class="token-icon">🤖</div>
            LLM Content Analyzer
            <div class="grade-badge grade-${analysis.grade}">${analysis.grade} (${analysis.totalScore}/100)</div>
          </h3>
        </div>
        <div class="token-content">
          <div class="tabs">
            <div class="tab active" data-tab="overview">Overview</div>
            <div class="tab" data-tab="llm-grade">LLM Grade</div>
            <div class="tab" data-tab="tokens">Tokens</div>
          </div>
          
          <div class="tab-content active" id="overview">
            <div class="token-section">
              <div class="section-title">Content Preview</div>
              <div class="text-preview">${visibleText.slice(0, 400)}${visibleText.length > 400 ? '\n\n... (showing first 400 characters)' : ''}</div>
            </div>
            
            <div class="token-section">
              <div class="section-title">Quick Stats</div>
              <div class="stats-grid">
                <div class="stat-card">
                  <div class="stat-value">${visibleText.length.toLocaleString()}</div>
                  <div class="stat-label">Characters</div>
                </div>
                <div class="stat-card">
                  <div class="stat-value">${visibleText.split(/\s+/).length.toLocaleString()}</div>
                  <div class="stat-label">Words</div>
                </div>
                <div class="stat-card">
                  <div class="stat-value">${analysis.tokenCount.toLocaleString()}</div>
                  <div class="stat-label">Est. Tokens</div>
                </div>
              </div>
            </div>
          </div>
          
          <div class="tab-content" id="llm-grade">
            <div class="token-section">
              <div class="section-title">LLM Friendliness Breakdown</div>
              <div class="llm-scores">
                <div class="score-item">
                  <span>Text Extraction</span>
                  <span class="score-value">${analysis.scores.textExtraction}/25</span>
                </div>
                <div class="score-item">
                  <span>HTML Structure</span>
                  <span class="score-value">${analysis.scores.semantic}/25</span>
                </div>
                <div class="score-item">
                  <span>Content Visibility</span>
                  <span class="score-value">${analysis.scores.visibility}/15</span>
                </div>
                <div class="score-item">
                  <span>Token Efficiency</span>
                  <span class="score-value">${analysis.scores.efficiency}/15</span>
                </div>
                <div class="score-item">
                  <span>Context Clarity</span>
                  <span class="score-value">${analysis.scores.context}/10</span>
                </div>
                <div class="score-item">
                  <span>Accessibility</span>
                  <span class="score-value">${analysis.scores.accessibility}/10</span>
                </div>
              </div>
              <div id="recommendations"></div>
            </div>
          </div>
          
          <div class="tab-content" id="tokens">
            <div class="token-section">
              <div class="section-title">Token Analysis</div>
              <button class="btn" id="showTokensBtn">
                🔢 Analyze Tokens
              </button>
              <button class="btn btn-secondary" id="copyTextBtn">
                📋 Copy Text
              </button>
              <div id="tokenOutput" class="token-output" style="display: none;"></div>
            </div>
          </div>
          
          <div class="token-section" style="border-bottom: none;">
            <button class="btn btn-danger" id="closePopup">
              ✕ Close
            </button>
          </div>
        </div>
      `;
      
      document.body.appendChild(popup);
      
      // Tab functionality
      document.querySelectorAll('.tab').forEach(tab => {
        tab.onclick = () => {
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
          tab.classList.add('active');
          document.getElementById(tab.dataset.tab).classList.add('active');
        };
      });
      
      // Generate recommendations
      function generateRecommendations() {
        const recs = [];
        if (analysis.scores.textExtraction < 20) {
          recs.push("⚠️ Text may not be in HTML source - check for image-based or JS-rendered content");
        }
        if (analysis.scores.semantic < 20) {
          recs.push("📝 Use semantic HTML: proper h1-h6 headings, p tags, lists");
        }
        if (analysis.scores.visibility < 10) {
          recs.push("👁️ Too much hidden content - ensure main text is visible");
        }
        if (analysis.scores.efficiency < 10) {
          recs.push("⚡ Improve token efficiency - remove repetitive text and fluff");
        }
        if (analysis.scores.context < 5) {
          recs.push("🏷️ Add meta title and description for better context");
        }
        if (analysis.scores.accessibility < 7) {
          recs.push("♿ Improve accessibility: alt text for images, descriptive links");
        }
        
        if (recs.length === 0) {
          recs.push("✅ Great job! This page is very LLM-friendly");
        }
        
        document.getElementById('recommendations').innerHTML = 
          '<div class="section-title" style="margin-top: 16px;">Recommendations</div>' +
          recs.map(rec => `<div style="margin-bottom: 8px; font-size: 13px;">${rec}</div>`).join('');
      }
      
      generateRecommendations();
      
      // Event handlers
      document.getElementById('closePopup').onclick = () => {
        popup.style.animation = 'slideIn 0.3s ease-out reverse';
        setTimeout(() => popup.remove(), 300);
      };
      
      document.getElementById('copyTextBtn').onclick = () => {
        navigator.clipboard.writeText(visibleText).then(() => {
          const btn = document.getElementById('copyTextBtn');
          const originalText = btn.innerHTML;
          btn.innerHTML = '✓ Copied!';
          btn.style.background = '#28a745';
          setTimeout(() => {
            btn.innerHTML = originalText;
            btn.style.background = '';
          }, 2000);
        });
      };
      
      document.getElementById('showTokensBtn').onclick = async () => {
        const btn = document.getElementById('showTokensBtn');
        const output = document.getElementById('tokenOutput');
        
        btn.disabled = true;
        btn.innerHTML = '<div class="spinner"></div>Loading...';
        output.style.display = 'block';
        output.innerHTML = '<div class="loading"><div class="spinner"></div>Loading tokenizer...</div>';
        
        try {
          await new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = 'https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/cl100k_base.js';
            script.onload = resolve;
            script.onerror = () => reject(new Error('Failed to load tokenizer.'));
            document.head.appendChild(script);
          });
          
          const { encode } = window.GPTTokenizer_cl100k_base;
          const tokens = encode(visibleText);
          const words = visibleText.split(/\s+/);
          const maxTokensToShow = 100;
          
          const tokenPairs = tokens.slice(0, maxTokensToShow).map((id, idx) => {
            const word = words[idx] || '...';
            return `${String(idx + 1).padStart(3, ' ')}: "${word}" → ${id}`;
          });
          
          const analysisResult = `Token Analysis Results
    ${'='.repeat(50)}
    
    📊 Statistics:
    • Total Tokens: ${tokens.length.toLocaleString()}
    • Characters: ${visibleText.length.toLocaleString()}
    • Words: ${words.length.toLocaleString()}
    • Chars/Token: ${(visibleText.length / tokens.length).toFixed(2)}
    • Compression: ${((1 - tokens.length / visibleText.length) * 100).toFixed(1)}%
    
    🔢 Token Mappings (first ${Math.min(maxTokensToShow, tokens.length)}):
    ${tokenPairs.join('\n')}${tokens.length > maxTokensToShow ? `\n\n... and ${(tokens.length - maxTokensToShow).toLocaleString()} more tokens` : ''}
    
    💡 LLM Context:
    • GPT-4 Context: ~128k tokens (${Math.round(tokens.length / 128000 * 100)}% used)
    • Claude Context: ~200k tokens (${Math.round(tokens.length / 200000 * 100)}% used)`;
          
          output.textContent = analysisResult;
          btn.innerHTML = '✓ Complete';
          btn.style.background = '#28a745';
          
        } catch (err) {
          output.textContent = '❌ Error loading tokenizer. Check internet connection.';
          btn.innerHTML = '❌ Error';
          btn.style.background = '#dc3545';
        }
      };
    })();
    

    What the Tool Shows:

    • A-F Grade with 100-point scoring system

    • Content preview showing what AI sees

    • 6 scoring categories: Text extraction, HTML structure, visibility, token efficiency, context clarity, accessibility

    • Specific recommendations for improvement

    • Token analysis with compression ratios and context usage

    It instantly identifies LLM optimization opportunities and provides actionable fixes for better AI discoverability.

Stay updated with our latest improvements

Uncover deep insights from employee feedback using advanced natural language processing.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Join the Founder’s Club

Unlock the full power of Flozi at the best price you’ll ever see.
As an early supporter, you’ll get lifetime updates, early access to upcoming features, and a front-row seat in shaping what comes next. Your belief in this tool helps us build it better.
pay as you go
$19/mo

$9/mo

$99
annually

Perfect if you’re just getting started with Flozi. You get full access to the editor, SEO features, and Notion-to-Webflow sync.

lifetime plan  (one license per domain)

$199

pay once,
use forever
100 Spots Left

This is a limited-time offer for early believers who want to support Flozi and use it forever—lifetime access, lifetime updates, and early access to everything new we build (excluding AI).