<?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: Rahul</title>
    <description>The latest articles on DEV Community by Rahul (@rahul_85ac39adcd5c87cfd93).</description>
    <link>https://dev.to/rahul_85ac39adcd5c87cfd93</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%2F4048697%2Ff441012b-3f65-44d0-b4ba-41a626512312.png</url>
      <title>DEV Community: Rahul</title>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rahul_85ac39adcd5c87cfd93"/>
    <language>en</language>
    <item>
      <title>I checked 95 well-known sites for broken link previews. 14% had none at all.</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Sun, 02 Aug 2026 00:26:26 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/i-checked-95-well-known-sites-for-broken-link-previews-14-had-none-at-all-269h</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/i-checked-95-well-known-sites-for-broken-link-previews-14-had-none-at-all-269h</guid>
      <description>&lt;p&gt;I checked the link-preview tags on 95 well-known sites. Under half were clean, and&lt;br&gt;
nine sites developers use constantly have &lt;strong&gt;no preview tags at all&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you have ever pasted a link into Slack and got a bare grey URL instead of a title&lt;br&gt;
and image, this is why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Of 95 sites, 79 responded to an automated check (the rest blocked it). Of those 79:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;count&lt;/th&gt;
&lt;th&gt;share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Perfect (100/100)&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;48%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing &lt;code&gt;og:title&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;23%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing &lt;code&gt;og:image&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No preview tags whatsoever&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;14%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;og:image&lt;/code&gt; that returns an error&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Nine sites with zero preview tags
&lt;/h2&gt;

&lt;p&gt;Each of these was re-checked by hand with a real Chrome user-agent to rule out&lt;br&gt;
bot-blocking. All returned HTTP 200 with no &lt;code&gt;og:*&lt;/code&gt; and no &lt;code&gt;twitter:*&lt;/code&gt; tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;news.ycombinator.com&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;python.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;swift.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ruby-lang.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;arxiv.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;jstor.org&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;arstechnica.com&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;trello.com&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;replicate.com&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hacker News having no link preview is almost a design statement. python.org,&lt;br&gt;
swift.org and ruby-lang.org are harder to explain — those are the front doors of&lt;br&gt;
three major languages, and every share of them renders as a naked URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  The subtler failure
&lt;/h2&gt;

&lt;p&gt;Missing tags are at least honest. The nastier case is tags that &lt;em&gt;look&lt;/em&gt; fine but point&lt;br&gt;
at an image that no longer loads — you keep sharing links believing the preview works,&lt;br&gt;
because you never see what other people see. One site in the sample had exactly this.&lt;/p&gt;

&lt;p&gt;Worth knowing: &lt;code&gt;og:image&lt;/code&gt; needs an &lt;strong&gt;absolute&lt;/strong&gt; URL. A relative path silently produces&lt;br&gt;
no image on most platforms, and nothing in your own browser will ever warn you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method, and where it is weak
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;95 sites chosen for recognisability across dev tools, languages, SaaS, news,
reference and community — not a ranked top-N list.&lt;/li&gt;
&lt;li&gt;Homepages only. Deeper pages often have tags the homepage lacks, so this measures
the front door, not the whole site.&lt;/li&gt;
&lt;li&gt;16 sites blocked the automated request. &lt;strong&gt;Blocked is reported as unknown, not as a
score of zero&lt;/strong&gt; — conflating "we could not check" with "this is broken" is the
easiest way to produce a wrong number, and I hit that bug while building this.&lt;/li&gt;
&lt;li&gt;Two sites were dropped from the final list: one was rate-limited, and reddit.com
returned 403 and 200 on different attempts, so its result was not stable enough
to publish.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Check your own
&lt;/h2&gt;

&lt;p&gt;I wrote the checker as an open-source tool. It validates Open Graph and Twitter Card&lt;br&gt;
tags, confirms the preview image actually loads, and also checks robots.txt and&lt;br&gt;
sitemap.xml. Free, no signup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live: &lt;a href="https://ogcheck.onrender.com" rel="noopener noreferrer"&gt;https://ogcheck.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source (MIT): &lt;a href="https://github.com/rahulatrkm/ogcheck" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/ogcheck&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a GitHub Action, so a build can fail when a page ships without a valid&lt;br&gt;
preview — which is the only way I know to stop this regressing quietly.&lt;/p&gt;

&lt;p&gt;If you run it on your own site and get a surprising result, I would genuinely like to&lt;br&gt;
hear it — especially any false positives, since that is the part I most want to fix.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a tool that explains any confusing document in plain words (your level, your language)</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Sat, 01 Aug 2026 10:31:21 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/i-built-a-tool-that-explains-any-confusing-document-in-plain-words-your-level-your-language-3155</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/i-built-a-tool-that-explains-any-confusing-document-in-plain-words-your-level-your-language-3155</guid>
      <description>&lt;h2&gt;
  
  
  Everyone keeps running into documents that gatekeep their own life
&lt;/h2&gt;

&lt;p&gt;A blood test full of abbreviations. A legal letter. A bank statement. A&lt;br&gt;
government form. A dense insurance policy. To understand your &lt;em&gt;own&lt;/em&gt; information&lt;br&gt;
you often need a professional — which costs time and money.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://plainly-n6ni.onrender.com" rel="noopener noreferrer"&gt;Plainly&lt;/a&gt;: paste any confusing text and get it back in plain&lt;br&gt;
language — &lt;strong&gt;at the reading level you choose&lt;/strong&gt; (from "like I'm 10" to "keep it&lt;br&gt;
precise") and &lt;strong&gt;in your language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You get a TL;DR, key points, things to watch out for (deadlines, anything that&lt;br&gt;
needs action), the hard words decoded, and practical next steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Paste a cryptic blood report like &lt;code&gt;Hb 9.2 g/dL, MCV 72 fL, ferritin 8 ng/mL&lt;/code&gt; and&lt;br&gt;
it comes back with: "Your blood test shows anemia — low red blood cells — most&lt;br&gt;
likely caused by not having enough iron," plus what each term means and what to&lt;br&gt;
do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  It also checks if something is real
&lt;/h2&gt;

&lt;p&gt;There's a second mode — &lt;strong&gt;RealCheck&lt;/strong&gt; — where you paste a suspicious message or a&lt;br&gt;
claim and it reasons calmly about whether it's plausible, calling out scam and&lt;br&gt;
misinformation red flags (urgency, pay-a-fee, prize-you-didn't-enter, crypto&lt;br&gt;
doubling, verify-your-account links) and how to check it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest about what it is
&lt;/h2&gt;

&lt;p&gt;It's an &lt;strong&gt;AI explainer/reasoner, not a doctor, lawyer or fact-checking oracle&lt;/strong&gt; —&lt;br&gt;
great for &lt;em&gt;understanding&lt;/em&gt; and for asking better questions, not a final authority.&lt;br&gt;
Nothing is stored, no signup, free.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try it: &lt;strong&gt;&lt;a href="https://plainly-n6ni.onrender.com" rel="noopener noreferrer"&gt;https://plainly-n6ni.onrender.com&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Open source (MIT): &lt;a href="https://github.com/rahulatrkm/plainly" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/plainly&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood it's a tiny Python (stdlib) backend forwarding to a free LLM, with&lt;br&gt;
a strict "JSON only" contract + retries to keep responses reliable. What kind of&lt;br&gt;
confusing document should I make it handle better?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a tool that reads your contract and flags the risky clauses in plain English</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Fri, 31 Jul 2026 09:30:57 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/i-built-a-tool-that-reads-your-contract-and-flags-the-risky-clauses-in-plain-english-55p4</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/i-built-a-tool-that-reads-your-contract-and-flags-the-risky-clauses-in-plain-english-55p4</guid>
      <description>&lt;h2&gt;
  
  
  The contract clause that almost cost my friend their side projects
&lt;/h2&gt;

&lt;p&gt;A friend nearly signed a freelance contract that assigned the company &lt;strong&gt;all&lt;/strong&gt; the&lt;br&gt;
IP they created — including personal side projects done on their own time — plus&lt;br&gt;
a 3-year industry-wide non-compete and net-90 payment terms. To them it just&lt;br&gt;
looked like normal legal boilerplate. It wasn't.&lt;/p&gt;

&lt;p&gt;Most of us sign leases, freelance agreements, NDAs and job offers we don't fully&lt;br&gt;
understand, because a lawyer costs hundreds and the language is deliberately&lt;br&gt;
dense. So I built a small tool to make contracts legible for non-lawyers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Paste a contract (or the clauses you're unsure about) into&lt;br&gt;
&lt;a href="https://clauseclear-app.azurewebsites.net" rel="noopener noreferrer"&gt;ClauseClear&lt;/a&gt; and it returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;plain-English summary&lt;/strong&gt; and a &lt;strong&gt;risk score&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;clauses that actually matter&lt;/strong&gt; — each with &lt;em&gt;what it means&lt;/em&gt;, &lt;em&gt;why it
matters&lt;/em&gt;, and &lt;em&gt;what to ask for instead&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;protections that seem to be missing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;questions to ask&lt;/strong&gt; before you sign&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's honest that it's an AI first-read, &lt;strong&gt;not legal advice&lt;/strong&gt; — but as a "should I&lt;br&gt;
worry about this?" gut-check before you sign, it's genuinely useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A tiny Python (WSGI, standard-library) backend forwards your text to a free,
OpenAI-compatible LLM and asks for a &lt;strong&gt;structured&lt;/strong&gt; review&lt;/li&gt;
&lt;li&gt;The frontend is a single static page — risk gauge, severity-colored clause
cards, copy-to-clipboard report&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing is stored.&lt;/strong&gt; No signup. Free to use.&lt;/li&gt;
&lt;li&gt;Open source (MIT): &lt;a href="https://github.com/rahulatrkm/clauseclear" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/clauseclear&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting the model to reliably return clean JSON (instead of chatty preamble or&lt;br&gt;
truncated output) was the fiddly part — solved with a strict "output only JSON"&lt;br&gt;
contract, reasoning-strip, truncated-JSON repair, and retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Paste something gnarly — an old lease, a gig contract, a ToS — and see what it&lt;br&gt;
flags: &lt;strong&gt;&lt;a href="https://clauseclear-app.azurewebsites.net" rel="noopener noreferrer"&gt;https://clauseclear-app.azurewebsites.net&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love feedback on the review quality: what did it miss, and is the "suggested&lt;br&gt;
pushback" actually useful or too generic?&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Generate invoice PDFs without a headless browser</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 17:13:48 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/generate-invoice-pdfs-without-a-headless-browser-3a99</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/generate-invoice-pdfs-without-a-headless-browser-3a99</guid>
      <description>&lt;h2&gt;
  
  
  You probably don't need Chromium to make a PDF
&lt;/h2&gt;

&lt;p&gt;The default advice for "generate a PDF" is HTML-to-PDF via headless Chromium&lt;br&gt;
(Puppeteer/Playwright). For arbitrary web pages, fine. For a &lt;strong&gt;document&lt;/strong&gt; with a&lt;br&gt;
known layout — an invoice, a receipt, a statement — it's the wrong tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~300MB of Chromium to ship and keep patched&lt;/li&gt;
&lt;li&gt;system libraries that break on minimal/serverless images&lt;/li&gt;
&lt;li&gt;seconds of cold-start on the first request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--no-sandbox&lt;/code&gt; foot-guns and memory tuning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For structured documents you need correct layout and correct math, not a&lt;br&gt;
browser.&lt;/p&gt;
&lt;h2&gt;
  
  
  The lighter approach: render straight from data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;InvoicePDF&lt;/a&gt; takes JSON and returns a PDF — no browser involved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://invoicepdf-app.azurewebsites.net/invoice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"number":"INV-1","currency":"USD","seller_name":"Me LLC",
       "buyer_name":"Acme Corp",
       "items":[{"description":"Consulting","quantity":8,"unit_price":120}],
       "tax_rate_percent":10}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; invoice.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood it's &lt;code&gt;fpdf2&lt;/code&gt; — pure Python, no system deps — so it starts&lt;br&gt;
instantly, sips memory, and hosts on a free tier like a static app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: get the money math right
&lt;/h2&gt;

&lt;p&gt;Never use floats for money (&lt;code&gt;0.1 + 0.2 != 0.3&lt;/code&gt;). Keep amounts as &lt;strong&gt;integer minor&lt;br&gt;
units&lt;/strong&gt; (cents) and format at the very end, so &lt;code&gt;$27.00 + 10% tax&lt;/code&gt; is exactly&lt;br&gt;
&lt;code&gt;$29.70&lt;/code&gt;. InvoicePDF does this internally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Live playground: &lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sample PDF: &lt;a href="https://invoicepdf-app.azurewebsites.net/sample" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net/sample&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open source (MIT): &lt;a href="https://github.com/rahulatrkm/invoicepdf" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/invoicepdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've been reaching for headless Chromium to make invoices, this is a much&lt;br&gt;
lighter path. Feedback welcome.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>serverless</category>
      <category>api</category>
    </item>
    <item>
      <title>Is your sitemap.xml quietly broken? A 1-line way to check</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 16:11:32 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/is-your-sitemapxml-quietly-broken-a-1-line-way-to-check-2l6e</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/is-your-sitemapxml-quietly-broken-a-1-line-way-to-check-2l6e</guid>
      <description>&lt;h2&gt;
  
  
  The sitemap you set up once and never checked again
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;sitemap.xml&lt;/code&gt; helps search engines discover and crawl your pages efficiently.&lt;br&gt;
But a single stray character makes the whole file invalid XML — and crawlers just&lt;br&gt;
silently skip it. Or it points at an old path after a migration. Or it's empty.&lt;br&gt;
&lt;strong&gt;Nothing tells you.&lt;/strong&gt; You just get crawled less thoroughly.&lt;/p&gt;

&lt;p&gt;I added a free sitemap check to &lt;a href="https://ogcheck-app.azurewebsites.net" rel="noopener noreferrer"&gt;OGCheck&lt;/a&gt; (alongside its Open Graph&lt;br&gt;
and robots.txt checks).&lt;/p&gt;

&lt;h2&gt;
  
  
  Check it in one request
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://ogcheck-app.azurewebsites.net/sitemap?url=https://your-site.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It confirms your sitemap is &lt;strong&gt;reachable&lt;/strong&gt; (not a 404/500), is &lt;strong&gt;valid XML&lt;/strong&gt;, and&lt;br&gt;
actually &lt;strong&gt;lists URLs&lt;/strong&gt; rather than being empty — and tells you how many.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sitemap problems that quietly cost you crawl budget
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Invalid XML&lt;/strong&gt; — one unescaped &lt;code&gt;&amp;amp;&lt;/code&gt; or stray tag breaks the whole file for
crawlers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty sitemap&lt;/strong&gt; — generated once, never repopulated after a CMS change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unreachable&lt;/strong&gt; — a 404 or 500 after a migration or a misconfigured route.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not referenced in robots.txt&lt;/strong&gt; — search engines have to guess it's there.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  While you're at it
&lt;/h2&gt;

&lt;p&gt;The same free API also checks your &lt;code&gt;robots.txt&lt;/code&gt; (&lt;code&gt;/robots?url=…&lt;/code&gt;) and your social&lt;br&gt;
preview / &lt;code&gt;og:image&lt;/code&gt; (&lt;code&gt;/check?url=…&lt;/code&gt;). It's zero-dependency (pure Python stdlib),&lt;br&gt;
open source: &lt;a href="https://github.com/rahulatrkm/ogcheck" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/ogcheck&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What else silently breaks your site's visibility that a one-request check could&lt;br&gt;
catch? Genuinely curious — feedback welcome.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to generate an invoice PDF in Python (2 clean ways)</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 16:11:18 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/how-to-generate-an-invoice-pdf-in-python-2-clean-ways-1i6i</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/how-to-generate-an-invoice-pdf-in-python-2-clean-ways-1i6i</guid>
      <description>&lt;h2&gt;
  
  
  How to generate an invoice PDF (without the usual pain)
&lt;/h2&gt;

&lt;p&gt;If you've tried to generate an invoice or receipt PDF programmatically, you know&lt;br&gt;
the options are all annoying: low-level PDF drawing, HTML-to-PDF via headless&lt;br&gt;
Chromium (heavy, slow, breaks on fonts), or a bloated reporting library. For a&lt;br&gt;
document, that's overkill.&lt;/p&gt;

&lt;p&gt;Here are two clean ways — a few lines of Python, or a single API call.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option A — one API call (no dependencies)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;InvoicePDF&lt;/a&gt; takes JSON and returns a PDF. From any language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://invoicepdf-app.azurewebsites.net/invoice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"number":"INV-1","currency":"USD","seller_name":"Me LLC",
       "buyer_name":"Acme Corp",
       "items":[{"description":"Consulting","quantity":8,"unit_price":120}],
       "tax_rate_percent":10}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; invoice.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it — &lt;code&gt;application/pdf&lt;/code&gt; comes back. Free tier, no signup to try. There's a&lt;br&gt;
live playground at &lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net&lt;/a&gt; where you can edit the JSON and see the PDF.&lt;/p&gt;
&lt;h2&gt;
  
  
  Option B — pure Python with fpdf2
&lt;/h2&gt;

&lt;p&gt;If you'd rather keep it in-process, &lt;code&gt;fpdf2&lt;/code&gt; is pure Python (no system libs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fpdf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FPDF&lt;/span&gt;

&lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FPDF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Helvetica&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INVOICE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Helvetica&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Consulting  8 x $120.00 = $960.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoice.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one thing people get wrong: money math
&lt;/h2&gt;

&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; use floats for money. &lt;code&gt;0.1 + 0.2 != 0.3&lt;/code&gt; in floating point, and on an&lt;br&gt;
invoice that becomes &lt;code&gt;$29.700000001&lt;/code&gt;. Store amounts as &lt;strong&gt;integer minor units&lt;/strong&gt;&lt;br&gt;
(cents), do the math in integers, and format at the end. InvoicePDF does this&lt;br&gt;
internally so totals are always exact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Live: &lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net&lt;/a&gt; · Sample: &lt;a href="https://invoicepdf-app.azurewebsites.net/sample" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net/sample&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open source (MIT): &lt;a href="https://github.com/rahulatrkm/invoicepdf" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/invoicepdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What would make it genuinely useful in your stack — logos, templates, webhooks?&lt;br&gt;
Feedback welcome.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>I made an invoice PDF API that doesn't need a headless browser</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 06:17:32 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/i-made-an-invoice-pdf-api-that-doesnt-need-a-headless-browser-4djg</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/i-made-an-invoice-pdf-api-that-doesnt-need-a-headless-browser-4djg</guid>
      <description>&lt;h2&gt;
  
  
  Generating a PDF shouldn't require a headless browser
&lt;/h2&gt;

&lt;p&gt;Every time I needed to generate an invoice or receipt PDF, the options were:&lt;br&gt;
wrestle a low-level PDF library, fight a templating engine, or spin up headless&lt;br&gt;
Chromium (slow, heavy, breaks on fonts, painful to host). For a &lt;em&gt;document&lt;/em&gt;, that&lt;br&gt;
felt absurd.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;InvoicePDF&lt;/a&gt;: &lt;strong&gt;POST JSON, get a clean invoice PDF back.&lt;/strong&gt;&lt;br&gt;
That's the whole thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://invoicepdf-app.azurewebsites.net/invoice &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "number": "INV-2026-001",
    "currency": "USD",
    "seller_name": "Your Company LLC",
    "buyer_name": "Acme Corp",
    "items": [
      { "description": "Consulting (hours)", "quantity": 8, "unit_price": 120 },
      { "description": "Software license", "quantity": 1, "unit_price": 299 }
    ],
    "tax_rate_percent": 10,
    "notes": "Thank you!"
  }'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; invoice.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why pure Python (no chromium)
&lt;/h2&gt;

&lt;p&gt;It's built on &lt;code&gt;fpdf2&lt;/code&gt; — a pure-Python PDF library — so there's &lt;strong&gt;no headless&lt;br&gt;
browser and no system dependencies.&lt;/strong&gt; That means it starts instantly, uses&lt;br&gt;
almost no memory, and deploys on a free tier like a static app. For structured&lt;br&gt;
documents (invoices, receipts, statements), you don't need a browser; you need&lt;br&gt;
correct layout and correct math.&lt;/p&gt;

&lt;h2&gt;
  
  
  The money math is exact
&lt;/h2&gt;

&lt;p&gt;Financial documents can't have floating-point drift. InvoicePDF does all money&lt;br&gt;
as &lt;strong&gt;integer minor units&lt;/strong&gt; (cents/paise) internally, so &lt;code&gt;$27.00 subtotal + 10%&lt;br&gt;
tax&lt;/code&gt; is exactly &lt;code&gt;$29.70&lt;/code&gt; — never &lt;code&gt;$29.700000001&lt;/code&gt;. It handles multiple currencies&lt;br&gt;
(including zero-decimal ones like JPY), fractional quantities (e.g. hours), tax,&lt;br&gt;
notes, and due dates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it / use it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live playground&lt;/strong&gt; (edit JSON, get a PDF): &lt;a href="https://invoicepdf-app.azurewebsites.net" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample PDF&lt;/strong&gt;: &lt;a href="https://invoicepdf-app.azurewebsites.net/sample" rel="noopener noreferrer"&gt;https://invoicepdf-app.azurewebsites.net/sample&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source (MIT)&lt;/strong&gt;: &lt;a href="https://github.com/rahulatrkm/invoicepdf" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/invoicepdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free tier is 100 invoices/mo, no signup. If you generate a lot, there's a cheap&lt;br&gt;
paid tier.&lt;/p&gt;

&lt;p&gt;What would make this actually useful in your stack — logo/branding, a hosted&lt;br&gt;
template editor, webhooks? Genuinely curious — feedback welcome.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>api</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The robots.txt mistake that hides your whole site from Google</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 05:11:05 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/the-robotstxt-mistake-that-hides-your-whole-site-from-google-20al</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/the-robotstxt-mistake-that-hides-your-whole-site-from-google-20al</guid>
      <description>&lt;h2&gt;
  
  
  One line can hide your whole site from Google
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Disallow: /&lt;/code&gt; in your &lt;code&gt;robots.txt&lt;/code&gt; tells every crawler to ignore your entire&lt;br&gt;
site. It's shockingly common — usually left over from a staging config that got&lt;br&gt;
copied to production. And nothing tells you: your pages just quietly stop&lt;br&gt;
ranking.&lt;/p&gt;

&lt;p&gt;I kept getting bitten by &lt;code&gt;robots.txt&lt;/code&gt; and &lt;code&gt;sitemap.xml&lt;/code&gt; issues, so I added free&lt;br&gt;
checks for them to &lt;a href="https://ogcheck-app.azurewebsites.net" rel="noopener noreferrer"&gt;OGCheck&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Check your robots.txt in one request
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://ogcheck-app.azurewebsites.net/robots?url=https://your-site.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It confirms the file is &lt;strong&gt;reachable&lt;/strong&gt;, &lt;strong&gt;parseable&lt;/strong&gt;, flags a &lt;strong&gt;site-wide block&lt;/strong&gt;,&lt;br&gt;
and tells you whether it points at your &lt;strong&gt;sitemap&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The robots.txt mistakes that quietly cost you traffic
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Disallow: /&lt;/code&gt;&lt;/strong&gt; — blocks everything. The classic staging-to-prod accident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing file&lt;/strong&gt; — crawlers assume everything is allowed, which may expose
pages you didn't mean to (and you lose the chance to point at your sitemap).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;Sitemap:&lt;/code&gt; line&lt;/strong&gt; — search engines crawl your site less efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking your CSS/JS&lt;/strong&gt; — Google renders pages; blocking assets can hurt how
it sees them.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  While you're at it, check your sitemap too
&lt;/h2&gt;

&lt;p&gt;A broken or empty &lt;code&gt;sitemap.xml&lt;/code&gt; hurts crawl efficiency the same quiet way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://ogcheck-app.azurewebsites.net/sitemap?url=https://your-site.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both checks are free, zero-dependency (pure Python stdlib), and open source:&lt;br&gt;
&lt;a href="https://github.com/rahulatrkm/ogcheck" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/ogcheck&lt;/a&gt;. There's also a social-preview check&lt;br&gt;
(&lt;code&gt;/check?url=…&lt;/code&gt;) that confirms your &lt;code&gt;og:image&lt;/code&gt; actually loads.&lt;/p&gt;

&lt;p&gt;Feedback welcome — what else silently breaks your site's visibility that a&lt;br&gt;
one-request check could catch?&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Your blog's link preview is probably broken — here's a 1-line CI check</title>
      <dc:creator>Rahul</dc:creator>
      <pubDate>Mon, 27 Jul 2026 04:54:24 +0000</pubDate>
      <link>https://dev.to/rahul_85ac39adcd5c87cfd93/your-blogs-link-preview-is-probably-broken-heres-a-1-line-ci-check-2mab</link>
      <guid>https://dev.to/rahul_85ac39adcd5c87cfd93/your-blogs-link-preview-is-probably-broken-heres-a-1-line-ci-check-2mab</guid>
      <description>&lt;h2&gt;
  
  
  The silent bug that quietly kills your click-through
&lt;/h2&gt;

&lt;p&gt;You add &lt;code&gt;&amp;lt;meta property="og:image" content="..."&amp;gt;&lt;/code&gt;, the preview looks fine when&lt;br&gt;
you test it, you ship. Weeks later the image gets moved, the CDN path changes, or&lt;br&gt;
it was a relative URL all along — and now every share is a blank card. Your&lt;br&gt;
click-through quietly drops and &lt;strong&gt;nothing alerts you.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Catch it in one request (or in CI)
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://ogcheck-app.azurewebsites.net" rel="noopener noreferrer"&gt;OGCheck&lt;/a&gt; to catch exactly this. It parses your Open Graph +&lt;br&gt;
Twitter Card tags, scores them, and — the key part most validators skip —&lt;br&gt;
&lt;strong&gt;actually requests the &lt;code&gt;og:image&lt;/code&gt; to confirm it returns HTTP 200.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; ogcheck https://your-site.com/blog/post
&lt;span class="c"&gt;# exits non-zero if og:image 404s or required tags are missing -&amp;gt; perfect for CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a JSON API and a GitHub Action too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rahulatrkm/ogcheck@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://your-site.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The 5 things that actually break previews
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The image URL 404s (most common)&lt;/li&gt;
&lt;li&gt;A relative URL instead of an absolute one&lt;/li&gt;
&lt;li&gt;A cached old preview on the platform (re-scrape to bust it)&lt;/li&gt;
&lt;li&gt;Wrong dimensions or file type (use PNG/JPG at 1200×630)&lt;/li&gt;
&lt;li&gt;Crawlers blocked by robots.txt or auth&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  It's a small "site health" suite now
&lt;/h2&gt;

&lt;p&gt;Same free API also checks the other things that silently break how your site&lt;br&gt;
shows up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /check?url=…&lt;/code&gt; — social preview (Open Graph + og:image loads)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /robots?url=…&lt;/code&gt; — robots.txt (catches an accidental site-wide &lt;code&gt;Disallow: /&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /sitemap?url=…&lt;/code&gt; — sitemap.xml (valid XML, reachable, lists URLs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's free, zero-dependency (pure Python stdlib), and open source:&lt;br&gt;
&lt;a href="https://github.com/rahulatrkm/ogcheck" rel="noopener noreferrer"&gt;https://github.com/rahulatrkm/ogcheck&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you monitor a lot of pages, I'm thinking about a paid "watch these URLs and&lt;br&gt;
alert me when a preview breaks" tier — would that be useful? Honest feedback&lt;br&gt;
very welcome, especially on false positives.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>python</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
