<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emma Watson</title>
    <description>The latest articles on DEV Community by Emma Watson (@emma-watson3).</description>
    <link>https://dev.to/emma-watson3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3948788%2F68370d2a-f4a5-4563-a2b6-398c299f03bf.png</url>
      <title>DEV Community: Emma Watson</title>
      <link>https://dev.to/emma-watson3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emma-watson3"/>
    <language>en</language>
    <item>
      <title>Stop Guessing Your Competitor's SEO Strategy—Start Analyzing It</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Sat, 27 Jun 2026 07:11:20 +0000</pubDate>
      <link>https://dev.to/emma-watson3/stop-guessing-your-competitors-seo-strategy-start-analyzing-it-p1j</link>
      <guid>https://dev.to/emma-watson3/stop-guessing-your-competitors-seo-strategy-start-analyzing-it-p1j</guid>
      <description>&lt;p&gt;When you're trying to figure out why a competitor keeps ranking above you, the first instinct is to manually dig through their blog posts, check their backlinks, and guess their keyword targets. But that approach is slow, subjective, and often incomplete.&lt;/p&gt;

&lt;p&gt;Most developers know that content strategy is a major ranking factor, but reverse-engineering it at scale is tough. Competitors might publish dozens of articles a month, each targeting different keywords with varying structures and internal linking patterns.&lt;/p&gt;

&lt;p&gt;This is where automated analysis becomes a game-changer. Instead of manually tracking every post, you can use a tool that scans a competitor's domain, identifies their content feed, and extracts the underlying SEO strategy.&lt;/p&gt;

&lt;p&gt;Here's a simple Python script to get a basic content inventory from a competitor's sitemap:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import requests&lt;br&gt;
import xml.etree.ElementTree as ET&lt;br&gt;
from urllib.parse import urlparse&lt;/p&gt;

&lt;p&gt;def get_competitor_urls(sitemap_url):&lt;br&gt;
    try:&lt;br&gt;
        response = requests.get(sitemap_url, timeout=10)&lt;br&gt;
        root = ET.fromstring(response.content)&lt;br&gt;
        namespace = {'ns': '&lt;a href="http://www.sitemaps.org/schemas/sitemap/0.9'" rel="noopener noreferrer"&gt;http://www.sitemaps.org/schemas/sitemap/0.9'&lt;/a&gt;}&lt;br&gt;
        urls = [loc.text for loc in root.findall('.//ns:loc', namespace)]&lt;br&gt;
        return urls[:20]  # Limit for demo&lt;br&gt;
    except Exception as e:&lt;br&gt;
        print(f"Error fetching sitemap: {e}")&lt;br&gt;
        return []&lt;/p&gt;

&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;competitor_sitemap = "&lt;a href="https://example-competitor.com/sitemap.xml" rel="noopener noreferrer"&gt;https://example-competitor.com/sitemap.xml&lt;/a&gt;"&lt;br&gt;
urls = get_competitor_urls(competitor_sitemap)&lt;br&gt;
for url in urls:&lt;br&gt;
    print(url)&lt;/p&gt;

&lt;p&gt;This gives you a list of their published pages. But to truly understand their strategy—like which keywords they target, how often they publish, and what content formats they use—you need deeper analysis.&lt;/p&gt;

&lt;p&gt;Tools like the SERPSpur Competitor Content Radar automate this entire process. You enter a competitor's domain, and the AI analyst finds their content feed, identifies topic clusters, and reverse-engineers their SEO approach. It surfaces patterns in keyword targeting, content length, and publishing frequency.&lt;/p&gt;

&lt;p&gt;Why does this matter for your SEO? Knowing what works for your competitors lets you replicate successful strategies, find content gaps they missed, and avoid wasting time on low-opportunity topics. It turns competitor research from a guessing game into a data-driven process.&lt;/p&gt;

&lt;p&gt;Whether you're building an SEO tool or just doing routine competitive analysis, having automated content radar can save hours and reveal insights you'd never spot manually.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LLM.txt: The AI-Era Version of Robots.txt Every Developer Should Know About</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Wed, 24 Jun 2026 11:46:24 +0000</pubDate>
      <link>https://dev.to/emma-watson3/llmtxt-the-ai-era-version-of-robotstxt-every-developer-should-know-about-nkf</link>
      <guid>https://dev.to/emma-watson3/llmtxt-the-ai-era-version-of-robotstxt-every-developer-should-know-about-nkf</guid>
      <description>&lt;p&gt;Ever had an AI crawler scrape your entire site and use it to train a model without your permission? It's becoming a real headache for developers who want control over how their content gets consumed by AI systems. That's where the LLM.txt file comes in - think of it as robots.txt but specifically designed for AI crawlers.&lt;/p&gt;

&lt;p&gt;Let's break down what an LLM.txt file actually does. It's a simple text file placed in your website's root directory that tells AI systems which parts of your content they can access and how they can use it. You can specify allowed paths, set usage policies, and even define rate limits for different AI crawlers.&lt;/p&gt;

&lt;p&gt;Here's a basic example of what your LLM.txt might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Allow: /blog/
Disallow: /private/
Rate-limit: 10 requests per minute
Usage: training-allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But here's where it gets interesting. You can get more granular with specific AI agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: GPTBot
Allow: /public/
Disallow: /api/
Usage: no-training

User-agent: Claude-Web
Allow: /
Usage: training-allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real power comes from configuring access rules dynamically. For instance, you might want to block all AI crawlers from accessing your API documentation while allowing them to read your blog posts. Or maybe you want to limit how frequently they can scrape your site to prevent server overload.&lt;/p&gt;

&lt;p&gt;One pattern I've found useful is setting up conditional access based on content types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Allow: /docs/
Allow: /tutorials/
Disallow: /admin/
Disallow: /drafts/
Usage: no-commercial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is being explicit about your intentions. Unlike robots.txt, which is more of a suggestion, LLM.txt is designed to be legally enforceable. You're essentially creating a contract between your site and AI systems.&lt;/p&gt;

&lt;p&gt;When I started implementing this for my projects, I used the SERPSpur LLM.txt Generator tool to handle the configuration. It made the process much smoother since it automatically generates the proper syntax and validates the file structure. But you can definitely write these manually if you prefer.&lt;/p&gt;

&lt;p&gt;Just remember to test your configuration before deploying. One wrong rule could accidentally block all AI traffic or expose content you meant to keep private. Start with a simple setup, monitor your logs, and adjust as needed.&lt;/p&gt;

&lt;p&gt;The bottom line? AI crawlers aren't going anywhere, so might as well set clear boundaries early. Your LLM.txt file is your best tool for maintaining control over how AI systems interact with your hard work.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>5. How I Audit Crawler Accessibility and Archival History for SEO</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Wed, 24 Jun 2026 04:28:49 +0000</pubDate>
      <link>https://dev.to/emma-watson3/5-how-i-audit-crawler-accessibility-and-archival-history-for-seo-1kl4</link>
      <guid>https://dev.to/emma-watson3/5-how-i-audit-crawler-accessibility-and-archival-history-for-seo-1kl4</guid>
      <description>&lt;p&gt;Ever inherited a website and wondered, "Has this page actually been crawled recently, or is it just sitting in Google's backlog?" Most people jump straight into Search Console, but that only tells part of the story.&lt;/p&gt;

&lt;p&gt;Sometimes you need a quick way to investigate how accessible a page is to search engine crawlers and whether historical crawl records exist. That's especially useful when troubleshooting indexing issues, content updates, or sudden ranking drops.&lt;/p&gt;

&lt;p&gt;One simple approach is to audit your site's URLs and look for pages that haven't been updated, crawled, or archived recently.&lt;/p&gt;

&lt;p&gt;For example, if you have a list of URLs, you can use Python to identify pages that may need further investigation:&lt;/p&gt;

&lt;p&gt;import csv&lt;/p&gt;

&lt;p&gt;urls = []&lt;/p&gt;

&lt;p&gt;with open("urls.csv", "r") as file:&lt;br&gt;
    reader = csv.reader(file)&lt;br&gt;
    for row in reader:&lt;br&gt;
        urls.append(row[0])&lt;/p&gt;

&lt;p&gt;print(f"Found {len(urls)} URLs to review.")&lt;/p&gt;

&lt;p&gt;for url in urls:&lt;br&gt;
    print(f"Checking: {url}")&lt;/p&gt;

&lt;p&gt;This doesn't tell you crawl history directly, but it helps create a list of URLs that deserve a deeper inspection.&lt;/p&gt;

&lt;p&gt;The next step is figuring out whether search engines and archival systems can actually access those pages. That's where manual investigation becomes time-consuming.&lt;/p&gt;

&lt;p&gt;Instead of checking individual services one by one, I've been using SERPSpur's Crawler Accessibility &amp;amp; Archival Forensics Tool:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpspur.com/tool/crawler-accessibility-archival-forensics/" rel="noopener noreferrer"&gt;https://serpspur.com/tool/crawler-accessibility-archival-forensics/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It provides a quick way to investigate crawler accessibility signals and archival information for a URL without digging through multiple platforms manually.&lt;/p&gt;

&lt;p&gt;Why is this useful?&lt;/p&gt;

&lt;p&gt;Diagnose indexing problems faster&lt;br&gt;
Verify crawler accessibility&lt;br&gt;
Review archival visibility&lt;br&gt;
Identify pages that may be difficult for bots to reach&lt;br&gt;
Support technical SEO audits&lt;/p&gt;

&lt;p&gt;One thing I've learned over the years is that many ranking problems aren't content problems at all. They're crawlability problems.&lt;/p&gt;

&lt;p&gt;A page can't rank if search engines struggle to access it.&lt;/p&gt;

&lt;p&gt;So before spending hours rewriting content or building links, it's worth running a quick accessibility and archival check. Sometimes the issue is much simpler than you think.&lt;/p&gt;

&lt;p&gt;For technical SEOs, developers, and site owners, it's a useful forensic step that can uncover issues hiding beneath the surface.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why Technical Trust Signals Matter More Than Most SEOs Realiz</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Tue, 23 Jun 2026 13:56:23 +0000</pubDate>
      <link>https://dev.to/emma-watson3/why-technical-trust-signals-matter-more-than-most-seos-realiz-klk</link>
      <guid>https://dev.to/emma-watson3/why-technical-trust-signals-matter-more-than-most-seos-realiz-klk</guid>
      <description>&lt;p&gt;When I start auditing a new client's website, I always begin with the same question: "Can I actually trust this domain to rank?" Technical SEO is full of metrics that promise to measure authority, but trust is something different entirely.&lt;/p&gt;

&lt;p&gt;Trust isn't just about link profiles or content quality. It's the sum of technical signals that tell Google (and users) your site is legitimate. I recently ran a full trust audit on a client site that had been hit by a manual action, and the results surprised even me.&lt;/p&gt;

&lt;p&gt;Here's the process I follow:&lt;/p&gt;

&lt;p&gt;First, check your SSL configuration. You'd be amazed how many sites still have mixed content warnings or outdated TLS versions. A proper HTTPS setup is the foundation of technical trust.&lt;/p&gt;

&lt;p&gt;Second, examine your security headers. Content Security Policy (CSP), X-Frame-Options, and HSTS headers tell browsers your site is safe. Missing headers can flag your site as potentially compromised.&lt;/p&gt;

&lt;p&gt;Third, evaluate your domain reputation. This includes checking against known spam databases, verifying WHOIS privacy, and ensuring your domain hasn't been flagged for suspicious activity.&lt;/p&gt;

&lt;p&gt;I built a quick Node.js script to check security headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkSecurityHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Strict-Transport-Security&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strict-transport-security&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Security-Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-security-policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Frame-Options&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-frame-options&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client site I was auditing had a missing CSP header and an expired SSL certificate. After fixing those issues, we saw a 15% improvement in organic click-through rates within two weeks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fezw5ypqstq68v13e82ne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fezw5ypqstq68v13e82ne.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I learned is that trust signals are invisible to most site owners but immediately visible to search engines. Your domain's technical health directly impacts how Google evaluates your authority.&lt;/p&gt;

&lt;p&gt;For a comprehensive check, I use the SERPSpur Trust Rate Checker at &lt;a href="https://serpspur.com/tool/serpspur-trust-rate-checker/" rel="noopener noreferrer"&gt;https://serpspur.com/tool/serpspur-trust-rate-checker/&lt;/a&gt; to analyze all these signals at once. It gives me a clear picture of where a domain stands technically.&lt;/p&gt;

&lt;p&gt;The takeaway? Don't ignore technical trust. It's the foundation your entire SEO strategy sits on. Fix your headers, update your SSL, and clean up your domain reputation. Your rankings will thank you.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why I Switched to SerpSpur for SEO Tracking and Site Audits</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Fri, 19 Jun 2026 07:19:41 +0000</pubDate>
      <link>https://dev.to/emma-watson3/why-i-switched-to-serpspur-for-seo-tracking-and-site-audits-144e</link>
      <guid>https://dev.to/emma-watson3/why-i-switched-to-serpspur-for-seo-tracking-and-site-audits-144e</guid>
      <description>&lt;p&gt;Looking for a lightweight alternative to Semrush or Ahrefs? I've been using SerpSpur for everything from keyword tracking to site health audits. Here's a quick curl example to check backlinks:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
curl -s "&lt;a href="https://serpspur.com/tool/backlink-gap/?domain=example.com&amp;amp;competitor=competitor.com" rel="noopener noreferrer"&gt;https://serpspur.com/tool/backlink-gap/?domain=example.com&amp;amp;competitor=competitor.com&lt;/a&gt;" | jq '.backlinks'&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy68x13f3g4us7zc0rbll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy68x13f3g4us7zc0rbll.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;__&lt;br&gt;
It gives you on-page and off-page details without the bloat. Perfect for solo devs who need a fast, free SEO toolkit. Start with the free tier and scale as needed.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Automated LLM.txt Generation to Control AI Crawler Access with Python</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Thu, 11 Jun 2026 11:35:31 +0000</pubDate>
      <link>https://dev.to/emma-watson3/how-i-automated-llmtxt-generation-to-control-ai-crawler-access-with-python-44lg</link>
      <guid>https://dev.to/emma-watson3/how-i-automated-llmtxt-generation-to-control-ai-crawler-access-with-python-44lg</guid>
      <description>&lt;p&gt;I recently needed to control how AI crawlers access my documentation site, so I built a small tool to generate LLM.txt files. Here's how you can do it with the SERPSpur API:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;API_KEY = "your_api_key_here"&lt;/p&gt;

&lt;p&gt;def generate_llm_txt(rules):&lt;br&gt;
    response = requests.post(&lt;br&gt;
        "&lt;a href="https://api.serpspur.com/v1/llm-txt/generate" rel="noopener noreferrer"&gt;https://api.serpspur.com/v1/llm-txt/generate&lt;/a&gt;",&lt;br&gt;
        headers={"Authorization": f"Bearer {API_KEY}"},&lt;br&gt;
        json={"rules": rules}&lt;br&gt;
    )&lt;br&gt;
    return response.text&lt;/p&gt;

&lt;h1&gt;
  
  
  Example rules to allow only certain AI agents
&lt;/h1&gt;

&lt;p&gt;rules = {&lt;br&gt;
    "user_agent": ["GPTBot", "Google-Extended"],&lt;br&gt;
    "disallow": ["/private/", "/api/"],&lt;br&gt;
    "allow": ["/public/", "/docs/"]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;llm_content = generate_llm_txt(rules)&lt;br&gt;
print(llm_content)&lt;/p&gt;

&lt;p&gt;This gives you fine-grained control over which AI systems can access your content and what they see. Have you implemented any LLM.txt configurations for your projects?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Python SQLite CLI Tool for Homeware Catalog Management</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:17:53 +0000</pubDate>
      <link>https://dev.to/emma-watson3/building-a-python-sqlite-cli-tool-for-homeware-catalog-management-l0e</link>
      <guid>https://dev.to/emma-watson3/building-a-python-sqlite-cli-tool-for-homeware-catalog-management-l0e</guid>
      <description>&lt;p&gt;I built a small CLI tool in Python to help me catalog homeware items for a personal interior design project. It uses SQLite to store product details and generates simple reports. Here's the core function for adding items:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import sqlite3&lt;/p&gt;

&lt;p&gt;def add_item(name, category, price, material):&lt;br&gt;
    conn = sqlite3.connect('homeware.db')&lt;br&gt;
    c = conn.cursor()&lt;br&gt;
    c.execute('''CREATE TABLE IF NOT EXISTS items&lt;br&gt;
                 (name TEXT, category TEXT, price REAL, material TEXT)''')&lt;br&gt;
    c.execute("INSERT INTO items VALUES (?, ?, ?, ?)", (name, category, price, material))&lt;br&gt;
    conn.commit()&lt;br&gt;
    conn.close()&lt;br&gt;
    print(f"Added {name} to the catalog.")&lt;/p&gt;

&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;add_item('Ceramic Vase', 'Vases', 29.99, 'Ceramic')&lt;br&gt;
add_item('Wall Mirror', 'Mirrors', 89.99, 'Glass')&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv5foyjzdoui8kgb3woj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv5foyjzdoui8kgb3woj.jpg" alt=" " width="360" height="441"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://infinitydecor.co.uk/collections/homeware" rel="noopener noreferrer"&gt;https://infinitydecor.co.uk/collections/homeware&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes it easy to track stylish accents like planters and candle holders across rooms. I love how it keeps everything organized. Have you used SQLite for any home-related projects?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Infinity Decor Product Rankings Change Across Devices</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Tue, 09 Jun 2026 14:16:15 +0000</pubDate>
      <link>https://dev.to/emma-watson3/how-infinity-decor-product-rankings-change-across-devices-4hoo</link>
      <guid>https://dev.to/emma-watson3/how-infinity-decor-product-rankings-change-across-devices-4hoo</guid>
      <description>&lt;p&gt;While browsing the &lt;strong&gt;&lt;a href="https://infinitydecor.co.uk/collections/iron-rim-lock" rel="noopener noreferrer"&gt;Iron Rim Lock&lt;/a&gt;&lt;/strong&gt; collection from Infinity Decor, I wanted a quick way to compare how product-related search results appear across different devices. I used this Python script to analyze desktop, mobile, and tablet SERP variations:&lt;/p&gt;

&lt;p&gt;import requests&lt;/p&gt;

&lt;p&gt;API_KEY = "your_api_key_here"&lt;/p&gt;

&lt;p&gt;def compare_device_results(query, location):&lt;br&gt;
    results = {}&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for device in ["desktop", "mobile", "tablet"]:&lt;br&gt;
    response = requests.get(
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "q": query,
        "location": location,
        "device": device,
        "num": 10
    }
)

data = response.json()
results[device] = [
    r['title'] for r in data.get('organic_results', [])
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;return results&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Example usage&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;comparison = compare_device_results(&lt;br&gt;
    "iron rim lock Infinity Decor",&lt;br&gt;
    "London, UK"&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;for device, titles in comparison.items():&lt;br&gt;
    print(f"\n{device.upper()} Results:")&lt;br&gt;
    for title in titles[:5]:&lt;br&gt;
        print(f"  - {title}")&lt;/p&gt;

&lt;p&gt;This helped reveal how search rankings and product visibility can shift depending on whether users are searching on desktop, mobile, or tablet devices. For eCommerce stores like Infinity Decor, these insights can be valuable for optimizing product pages, improving mobile SEO, and understanding customer search behavior across platforms.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Automated Product Schema Markup for Thousands of E-Commerce Products</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Fri, 05 Jun 2026 06:54:46 +0000</pubDate>
      <link>https://dev.to/emma-watson3/how-i-automated-product-schema-markup-for-thousands-of-e-commerce-products-4ap1</link>
      <guid>https://dev.to/emma-watson3/how-i-automated-product-schema-markup-for-thousands-of-e-commerce-products-4ap1</guid>
      <description>&lt;p&gt;I've been optimizing a large e-commerce site and needed to generate Product &lt;a href="https://serpspur.com/tool/schema-markup-generator-json-ld/" rel="noopener noreferrer"&gt;schema markup&lt;/a&gt; for thousands of items. Doing this manually was impossible, so I built a pipeline that uses the SERPspur schema generator.&lt;/p&gt;

&lt;p&gt;Here's the core logic:&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
const axios = require('axios');&lt;/p&gt;

&lt;p&gt;async function generateProductSchema(product) {&lt;br&gt;
  const response = await axios.post&lt;br&gt;
    type: 'Product',&lt;br&gt;
    name: product.name,&lt;br&gt;
    description: product.description,&lt;br&gt;
    sku: product.sku,&lt;br&gt;
    offers: {&lt;br&gt;
      price: product.price,&lt;br&gt;
      priceCurrency: 'USD',&lt;br&gt;
      availability:&lt;br&gt;
    }&lt;br&gt;
  });&lt;br&gt;
  return response.data;}&lt;/p&gt;

&lt;p&gt;// Usage&lt;br&gt;
const products = await fetchAllProducts();&lt;br&gt;
const schemas = await Promise.all(products.map(generateProductSchema);&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccbr7pyik04484npn4bt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccbr7pyik04484npn4bt.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key is that the API ensures all required fields are present and formats the output correctly. For example, it automatically wraps offers in the proper structure and adds &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Google personalizes results based on your IP</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Mon, 01 Jun 2026 17:14:13 +0000</pubDate>
      <link>https://dev.to/emma-watson3/google-personalizes-results-based-on-your-ip-516b</link>
      <guid>https://dev.to/emma-watson3/google-personalizes-results-based-on-your-ip-516b</guid>
      <description>&lt;p&gt;Ever noticed how your search results look completely different when you use a VPN? That's because Google personalizes results based on your IP, not just your query. This is a nightmare for SEO pros trying to audit local visibility.&lt;/p&gt;

&lt;p&gt;I built a Python script that bypasses this by sending requests with custom headers and geolocation data. Here's a simplified version:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;headers = {&lt;br&gt;
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',&lt;br&gt;
    'Accept-Language': 'en-US,en;q=0.9',&lt;br&gt;
    'X-Forwarded-For': '8.8.8.8'  # spoof IP&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;params = {&lt;br&gt;
    'q': 'coffee shop',&lt;br&gt;
    'gl': 'us',  # country&lt;br&gt;
    'hl': 'en',  # language&lt;br&gt;
    'uule': 'w+CAIQICINVXNhIE5ldyBZb3Jr'  # encoded location&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;response = requests.get('&lt;a href="https://www.google.com/search" rel="noopener noreferrer"&gt;https://www.google.com/search&lt;/a&gt;', headers=headers, params=params)&lt;br&gt;
print(response.text[:500])  # check if results are localized&lt;/p&gt;

&lt;p&gt;This is great for one-off tests, but managing multiple locations and languages quickly becomes tedious. That's why I now use a dedicated tool that automates all this with a simple API call. It's been a game-changer for my international SEO workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpspur.com" rel="noopener noreferrer"&gt;https://serpspur.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
    </item>
    <item>
      <title>Tracking Keyword Rankings with Python + CSV: A Lightweight SEO Experiment</title>
      <dc:creator>Emma Watson</dc:creator>
      <pubDate>Fri, 29 May 2026 15:35:39 +0000</pubDate>
      <link>https://dev.to/emma-watson3/tracking-keyword-rankings-with-python-csv-a-lightweight-seo-experiment-2nlc</link>
      <guid>https://dev.to/emma-watson3/tracking-keyword-rankings-with-python-csv-a-lightweight-seo-experiment-2nlc</guid>
      <description>&lt;p&gt;I've been experimenting with a lightweight approach to track keyword ranking changes using Python and a simple CSV file. Here's the gist:&lt;/p&gt;

&lt;p&gt;python&lt;br&gt;
import csv&lt;br&gt;
import requests&lt;br&gt;
from datetime import datetime&lt;/p&gt;

&lt;p&gt;def check_ranking(keyword, url):&lt;br&gt;
    # Simplified ranking check - actual implementation would use search API&lt;br&gt;
    # This is just a placeholder&lt;br&gt;
    return {'keyword': keyword, 'url': url, 'rank': 5, 'date': datetime.now().isoformat()}&lt;/p&gt;

&lt;p&gt;def update_tracker(csv_path, keywords):&lt;br&gt;
    with open(csv_path, 'a', newline='') as csvfile:&lt;br&gt;
        writer = csv.DictWriter(csvfile, fieldnames=['keyword', 'url', 'rank', 'date'])&lt;br&gt;
        if csvfile.tell() == 0:&lt;br&gt;
            writer.writeheader()&lt;br&gt;
        for keyword in keywords:&lt;br&gt;
            data = check_ranking(keyword['url'], keyword['url'])&lt;br&gt;
            writer.writerow(data)&lt;/p&gt;

&lt;p&gt;keywords = [&lt;br&gt;
    {'keyword': 'python tutorial', 'url': '&lt;a href="https://example.com/python'" rel="noopener noreferrer"&gt;https://example.com/python'&lt;/a&gt;},&lt;br&gt;
    {'keyword': 'web scraping', 'url': '&lt;a href="https://example.com/scraping'" rel="noopener noreferrer"&gt;https://example.com/scraping'&lt;/a&gt;}&lt;br&gt;
]&lt;br&gt;
update_tracker('rankings.csv', keywords)&lt;/p&gt;

&lt;p&gt;For serious rank tracking, I rely on SERPSpur's API which handles search result parsing and historical data. But this simple approach works for hobby projects. How do you track your keyword rankings?&lt;/p&gt;

</description>
      <category>python</category>
      <category>keywordtracking</category>
    </item>
  </channel>
</rss>
