<?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: Convertica</title>
    <description>The latest articles on DEV Community by Convertica (@convertica).</description>
    <link>https://dev.to/convertica</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%2F4028779%2Fabe24959-acae-4c7b-8dba-b982102381a1.png</url>
      <title>DEV Community: Convertica</title>
      <link>https://dev.to/convertica</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/convertica"/>
    <language>en</language>
    <item>
      <title>Half the directories promising you a dofollow backlink are serving nofollow</title>
      <dc:creator>Convertica</dc:creator>
      <pubDate>Mon, 10 Aug 2026 14:26:07 +0000</pubDate>
      <link>https://dev.to/convertica/half-the-directories-promising-you-a-dofollow-backlink-are-serving-nofollow-ikn</link>
      <guid>https://dev.to/convertica/half-the-directories-promising-you-a-dofollow-backlink-are-serving-nofollow-ikn</guid>
      <description>&lt;p&gt;I spent a day submitting a side project to launch directories, and I made a rule for myself before I started: no listing goes live until I have measured what its outbound link actually looks like. Not what the pricing page claims. What the HTML says.&lt;/p&gt;

&lt;p&gt;I looked at about fifteen. Six of them do not give you the link they advertise. One advertises it in a way that is technically true and practically useless. And one had already quietly downgraded a link I earned weeks ago, without telling me.&lt;/p&gt;

&lt;p&gt;Here is the measuring, the results, and the two traps I walked into so you do not have to.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement is one curl and one grep
&lt;/h2&gt;

&lt;p&gt;Everything below comes from this. No tools, no subscriptions.&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;-sL&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/127 Safari/537.36"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://directory.example/listing/some-product"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; page.html

&lt;span class="c"&gt;# 1. Is the listing page even indexable?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oiE&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;meta[^&amp;gt;]+name="robots"[^&amp;gt;]*&amp;gt;'&lt;/span&gt; page.html

&lt;span class="c"&gt;# 2. What does the link to the product's own site look like?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oE&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;a [^&amp;gt;]*href="https?://theproduct\.com[^"]*"[^&amp;gt;]*&amp;gt;'&lt;/span&gt; page.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things matter in the output, and people usually check only the second one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a &lt;code&gt;&amp;lt;meta name="robots"&amp;gt;&lt;/code&gt; with &lt;code&gt;noindex&lt;/code&gt;?&lt;/strong&gt; A dofollow link on a page Google will not index is worth roughly nothing. Two of the directories I checked are &lt;code&gt;noindex&lt;/code&gt; on exactly the page that carries your link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the anchor carry &lt;code&gt;nofollow&lt;/code&gt;?&lt;/strong&gt; &lt;code&gt;rel="noopener noreferrer"&lt;/code&gt; is a dofollow link. &lt;code&gt;rel="nofollow noopener noreferrer"&lt;/code&gt; is not. That single word is the whole product being sold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; at all?&lt;/strong&gt; This is the one that surprised me, and I will come back to it.&lt;/p&gt;

&lt;p&gt;Do this on &lt;strong&gt;three or four different listings, not one&lt;/strong&gt;, and pick listings that look like free ones rather than the ones featured on the homepage. That is the entire trick, and it is the reason the numbers below look nothing like the marketing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tier-gated: the word "do-follow" appears only in the paid column.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One large launch board states it plainly in its own FAQ, which I only found after checking the listings:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Free launches need the badge on your site and wait their turn in the queue. Premium skips both: you choose the exact date, get a guaranteed homepage feature, and keep a permanent do-follow backlink, with no badge required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The free column lists "public product listing" and "badge required on your site" and says nothing about &lt;code&gt;rel&lt;/code&gt;. I sampled eight live listings: four came back &lt;code&gt;rel="noopener noreferrer"&lt;/code&gt;, four came back &lt;code&gt;rel="nofollow noopener noreferrer"&lt;/code&gt;. A clean split. Their own JavaScript settles it, because the launch form carries a per-plan flag called &lt;code&gt;backlink&lt;/code&gt; and a paid add-on to switch it on.&lt;/p&gt;

&lt;p&gt;So the free tier there is: host our badge forever, get a nofollow link. That is not a trade, that is a favour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Silently downgraded after the fact.&lt;/strong&gt; I had a badge in my footer from a directory that promised three dofollow links in exchange for it. I measured it again on the way past. All three links now read &lt;code&gt;rel="nofollow noopener noreferrer"&lt;/code&gt;. Nobody emailed me. The badge had been working for free for weeks. It is out of the footer now.&lt;/p&gt;

&lt;p&gt;The lesson is not that they are villains. It is that a badge-for-link deal is one you have to re-check, because only one side of it is enforced automatically. They verify your badge on a schedule. Nobody verifies their &lt;code&gt;rel&lt;/code&gt; but you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No link whatsoever.&lt;/strong&gt; This is the one worth knowing about. On the big software review sites in one particular network, I could not find the vendor's link at all. Not nofollow. Absent. The "Visit Website" control is a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, the redirect happens in JavaScript, and the header of the page says the quiet part out loud:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We may earn a referral fee when you visit a vendor through our links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which makes sense once you say it: a tracked affiliate redirect is not a citation, and there is no reason for them to make it one. If you are chasing those listings, chase them for the buyer traffic and the reviews. There is no link to win.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The no-op &lt;code&gt;rel&lt;/code&gt; token.&lt;/strong&gt; One directory ships &lt;code&gt;rel="noopener noreferrer dofollow"&lt;/code&gt;. There is no such thing as &lt;code&gt;rel="dofollow"&lt;/code&gt;. It is a token search engines ignore entirely; the link is dofollow because &lt;code&gt;nofollow&lt;/code&gt; is absent, not because somebody typed the opposite. Harmless in itself, but seeing it told me something about how carefully the rest of the site was built, and its product pages turned out to be &lt;code&gt;noindex&lt;/code&gt; anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the honest ones.&lt;/strong&gt; Two sites measured exactly as advertised. One free tier says "get 1 dofollow link" and means it. Another puts "permanent dofollow backlink" in the free column, and its live listings are server-rendered &lt;code&gt;index, follow&lt;/code&gt; with &lt;code&gt;rel="noopener noreferrer"&lt;/code&gt; on the product link. On a third, I sampled eight random launches and got eight dofollow links with no nofollow anywhere, which told me its &lt;code&gt;rel&lt;/code&gt; is not tier-gated at all: what its paid tier sells is homepage placement, not link equity.&lt;/p&gt;

&lt;p&gt;Those three got a badge in my footer, and I would do it again. The point of measuring is not that directories are a scam. It is that you can tell the fair ones from the rest in two minutes, and then spend your footer on the fair ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two traps I walked into
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I broke my own audit with a hostname filter.&lt;/strong&gt; My first pass over one directory reported "no outbound links found" on every listing, which was nonsense. My script excluded any anchor whose tag mentioned the directory's own domain, to skip internal navigation. But their outbound link looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://theproduct.app/?ref=https%3A%2F%2Fdirectory.example%2F"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory's domain sits inside the &lt;code&gt;ref&lt;/code&gt; parameter, so my filter threw away the exact link I was measuring. If an audit tells you a page has zero outbound links, suspect the audit first. Filter on the parsed hostname of the &lt;code&gt;href&lt;/code&gt;, not on the raw tag text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your bot protection can make your badge invisible.&lt;/strong&gt; Several of these sites verify the badge by fetching your homepage from their own servers and looking for it. If you sit behind a bot-challenge product, those datacenter requests can get a JavaScript interstitial instead of your HTML, and verification fails while the badge is plainly there in a browser.&lt;/p&gt;

&lt;p&gt;I could not see their side, so I reproduced what I could: from my own IP the page returned the badge under every &lt;code&gt;Accept-Language&lt;/code&gt; variant and under &lt;code&gt;python-requests&lt;/code&gt;, &lt;code&gt;node-fetch&lt;/code&gt;, &lt;code&gt;axios&lt;/code&gt;, &lt;code&gt;Go-http-client&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt; user agents. So neither the UA nor the cache was the problem. The proof came from the directory itself: on its review step, its own metadata crawler had filled my product title in as &lt;strong&gt;"Just a moment..."&lt;/strong&gt;, which is the title of a Cloudflare challenge page. Their crawler had been talking to the challenge, not to me.&lt;/p&gt;

&lt;p&gt;Two other directories' verifiers sailed through on the same day, so this is per-crawler, not a blanket block. Turning the protection off for the length of one verification click fixed it. If a verifier insists your badge is missing, check whether the site can see your HTML at all before you start editing your footer, and if the directory offers DNS TXT verification instead, that path skips the fetch entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell myself before starting
&lt;/h2&gt;

&lt;p&gt;Check &lt;code&gt;robots&lt;/code&gt;, check &lt;code&gt;rel&lt;/code&gt;, and check that an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; exists, on three or four &lt;strong&gt;free&lt;/strong&gt; listings. Do it before you spend a footer slot, because footer slots are finite and every badge is a permanent obligation the other side will keep checking. Re-measure the badges you already have, because at least one of mine had gone nofollow without a word. And keep the row short. Six badges reads as a community. Twenty reads as a link scheme.&lt;/p&gt;

&lt;p&gt;None of this is exotic. It is a curl, a grep, and the discipline to look at the free tier instead of the pricing table.&lt;/p&gt;




&lt;p&gt;I write these while building &lt;a href="https://convertica.net/" rel="noopener noreferrer"&gt;Convertica&lt;/a&gt;, a set of browser PDF and image tools with no signup wall, which is the side project I was submitting all day. The engineering half of the story is mostly fonts: getting text you type into a PDF to come out as real selectable text in Cyrillic, Arabic and Devanagari instead of boxes is most of the work behind &lt;a href="https://convertica.net/en/pdf-editor/" rel="noopener noreferrer"&gt;the editor&lt;/a&gt;, and it is a better story than directory &lt;code&gt;rel&lt;/code&gt; attributes. Maybe next time.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>A honeypot field made every Arabic page on my site render blank</title>
      <dc:creator>Convertica</dc:creator>
      <pubDate>Mon, 03 Aug 2026 17:46:01 +0000</pubDate>
      <link>https://dev.to/convertica/a-honeypot-field-made-every-arabic-page-on-my-site-render-blank-3aji</link>
      <guid>https://dev.to/convertica/a-honeypot-field-made-every-arabic-page-on-my-site-render-blank-3aji</guid>
      <description>&lt;p&gt;Convertica runs in seven languages. Six of them read left to right, and Arabic does not. That single difference cost me an embarrassing amount of debugging time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;Every Arabic converter page looked completely normal in my browser. Then I ran Lighthouse against one of them and the screenshot came back empty. Not broken, not half painted. White.&lt;/p&gt;

&lt;p&gt;Same URL, same server, same HTML. Fine in Chrome, blank in headless Chrome. And headless Chrome is roughly what Google, Bing and every link preview bot see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The culprit
&lt;/h2&gt;

&lt;p&gt;Sitting in the form on every converter page was a spam honeypot. An input no human should ever fill in, parked far outside the viewport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;
       &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"position: absolute; left: -9999px; opacity: 0"&lt;/span&gt;
       &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"-1"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"off"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the oldest tricks in the book, and it is harmless. In a left to right document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why direction changes everything
&lt;/h2&gt;

&lt;p&gt;In an LTR document, overflow past the left edge is unreachable. The browser clips it, no scrollbar appears, nothing moves. The honeypot sits in dead space.&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;dir="rtl"&lt;/code&gt; and the scroll origin moves to the right edge. Now that leftward overflow is real scrollable canvas, so the document is about ten thousand pixels wide with the actual content bunched up at the far right.&lt;/p&gt;

&lt;p&gt;My browser opens an RTL page already scrolled to its origin, so I never saw anything wrong. A headless renderer taking a screenshot starts at x = 0, which in that document is the far left corner. Nine thousand pixels of nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;One property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* before */&lt;/span&gt;
&lt;span class="nt"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;absolute&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nt"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;-9999px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nt"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* after */&lt;/span&gt;
&lt;span class="nt"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;absolute&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nt"&gt;inset-inline-start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;-9999px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nt"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;inset-inline-start&lt;/code&gt; is the logical form of &lt;code&gt;left&lt;/code&gt;. It follows the writing direction, resolving to &lt;code&gt;left&lt;/code&gt; in LTR and &lt;code&gt;right&lt;/code&gt; in RTL. The honeypot lands outside the viewport on the side the document is already ignoring, and the canvas never grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took from it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every offscreen hack you inherited from a 2010 blog post deserves a second look once you ship RTL. Honeypots, skip links, hidden measurement divs, homegrown sr-only classes. Trade &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; for &lt;code&gt;inset-inline-start&lt;/code&gt; and &lt;code&gt;inset-inline-end&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your own browser is the worst possible test for this class of bug, because it hides the failure by scrolling to the correct origin for you. Render the page headless and look at the actual pixels.&lt;/li&gt;
&lt;li&gt;If one locale quietly stops earning impressions while the rest are fine, suspect the renderer before you suspect the content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Arabic pages have been rendering properly for a while now. The tools live over at &lt;a href="https://convertica.net" rel="noopener noreferrer"&gt;Convertica&lt;/a&gt;, and the &lt;a href="https://convertica.net/ar/" rel="noopener noreferrer"&gt;Arabic side&lt;/a&gt; is the one that taught me this.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>seo</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Convert PDFs and Office files without leaving Claude or Cursor</title>
      <dc:creator>Convertica</dc:creator>
      <pubDate>Fri, 17 Jul 2026 22:09:38 +0000</pubDate>
      <link>https://dev.to/convertica/convert-pdfs-and-office-files-without-leaving-claude-or-cursor-ggl</link>
      <guid>https://dev.to/convertica/convert-pdfs-and-office-files-without-leaving-claude-or-cursor-ggl</guid>
      <description>&lt;p&gt;I kept hitting the same tiny annoyance. I would be deep in a chat with Claude, working through some documents, and then I would need one of them as a Word file. Or a client would send a HEIC photo that nothing wanted to open. Every time it meant leaving the editor, finding a converter site, uploading, downloading, and coming back. Small friction, but it adds up over a day.&lt;/p&gt;

&lt;p&gt;So I wired the conversion step directly into the assistant using MCP. Now I just ask for it in plain language and the file lands in my folder. This post shows how to set that up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP gives you here
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol lets an AI client call external tools in a structured way. Instead of the model guessing or writing throwaway scripts, it calls a real tool with real arguments and gets a real result back. A conversion server is a good fit: the model does not need to know how to render a PDF, it just needs to know that a &lt;code&gt;convert_file&lt;/code&gt; tool exists and what it accepts.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://convertica.net" rel="noopener noreferrer"&gt;Convertica&lt;/a&gt; MCP server because it wraps a whole batch of conversions behind two tools, but the pattern applies to any MCP server you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;You need Node 18 or newer and an MCP client. I will show Claude Code and the generic config that Cursor, Windsurf and Claude Desktop all understand.&lt;/p&gt;

&lt;p&gt;You also need an API key. Convertica issues one from the account dashboard once you have a subscription, and the same key works for the web API and the MCP server.&lt;/p&gt;

&lt;p&gt;Claude Code, one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add convertica &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CONVERTICA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cvk_live_xxxx &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; convertica-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any other client, drop this into the MCP config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"convertica"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"convertica-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"CONVERTICA_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cvk_live_xxxx"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole install. &lt;code&gt;npx&lt;/code&gt; pulls the package on first run, so there is nothing to clone or build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;

&lt;p&gt;Once the server is connected, you talk to it the way you talk about anything else. A few that I actually use:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Convert ~/Downloads/contract.pdf to Word&lt;/p&gt;

&lt;p&gt;Merge these three PDFs into one and compress the result&lt;/p&gt;

&lt;p&gt;Turn this HEIC photo into a JPG&lt;/p&gt;

&lt;p&gt;Render &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; as a PDF&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The model picks the right tool, reads the local file, sends it off, and writes the result next to the original. If you are curious what is available, there is a &lt;code&gt;list_converters&lt;/code&gt; tool that returns the full catalog with each tool's options, so you can ask "what can you convert?" and get an honest answer instead of a hallucinated one.&lt;/p&gt;

&lt;p&gt;Under the hood there are two tools. &lt;code&gt;list_converters&lt;/code&gt; returns the catalog. &lt;code&gt;convert_file&lt;/code&gt; takes a tool name, one or more local file paths, and an options object, then saves the output. Everything is typed, so the model gets a clear error if it asks for something that does not exist rather than failing silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a hosted converter instead of a local library
&lt;/h2&gt;

&lt;p&gt;You could do a lot of this locally with libraries. I went with a hosted API for two reasons.&lt;/p&gt;

&lt;p&gt;The first is coverage. PDF to Word done well is genuinely hard, and so is Office rendering, HEIC decoding, and PDF/A conformance. Stitching together five libraries and keeping them working is a project in itself. One API that already handles thirty five conversions is less code I own.&lt;/p&gt;

&lt;p&gt;The second is that it keeps the client thin. The MCP server is a small wrapper with no native dependencies, so &lt;code&gt;npx&lt;/code&gt; just works on any machine without a build step or a headless browser.&lt;/p&gt;

&lt;p&gt;The tradeoff is that files leave your machine for the conversion. Convertica deletes processed files right after the response, which was good enough for my use, but if you are handling something sensitive, read the provider's retention policy first and decide for yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The setup is a few minutes and the payoff is that a whole category of context switching disappears. Ask for the file you want in the format you want, keep working.&lt;/p&gt;

&lt;p&gt;The server is open source (MIT) if you want to read it or adapt the pattern to your own API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/convertica-net/convertica-mcp" rel="noopener noreferrer"&gt;https://github.com/convertica-net/convertica-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/convertica-mcp" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/convertica-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The API it calls: &lt;a href="https://convertica.net/api/" rel="noopener noreferrer"&gt;https://convertica.net/api/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build something similar for a different service, I would like to see it. The two-tool shape (a catalog tool plus a typed action tool) turned out to be a clean way to expose a broad API to an assistant without overwhelming it.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>productivity</category>
      <category>ai</category>
      <category>pdf</category>
    </item>
    <item>
      <title>Automating the PDF Conversions You Keep Doing by Hand</title>
      <dc:creator>Convertica</dc:creator>
      <pubDate>Tue, 14 Jul 2026 13:48:34 +0000</pubDate>
      <link>https://dev.to/convertica/automating-the-pdf-conversions-you-keep-doing-by-hand-4d0d</link>
      <guid>https://dev.to/convertica/automating-the-pdf-conversions-you-keep-doing-by-hand-4d0d</guid>
      <description>&lt;p&gt;Most PDF work is a one-off: a file lands, you convert it, you move on. But some of it repeats. A folder of scanned invoices every Monday. Statements that need to become spreadsheets before month-end. Reports that arrive as PDF and have to go out as Word. If you are doing the same conversion by hand every week, that is a job for a script, not a person.&lt;/p&gt;

&lt;p&gt;Here is how I moved those repeat conversions off my plate.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, the ten-second check that saves you
&lt;/h2&gt;

&lt;p&gt;Before automating anything, know which kind of PDF you are feeding the pipeline. Select a word in the file. If it highlights, the text is real and conversion is clean and deterministic. If nothing highlights, the page is an image, and you need OCR in the loop, which is still fine but adds a recognition step you should spot-check. Automations break most often because someone assumed every input was a native PDF when half of them were scans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping a converter in a script
&lt;/h2&gt;

&lt;p&gt;The pattern is boring in the best way: watch a folder or a queue, POST each file to a conversion endpoint, write the result somewhere. I use &lt;a href="https://convertica.net/" rel="noopener noreferrer"&gt;Convertica&lt;/a&gt; for the conversion step because it has a free API and does not require an account, so there is no OAuth dance to script around. A single conversion is just a POST with the file:&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://convertica.net/api/v1/pdf-to-word/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@invoice.pdf"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; invoice.docx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop that into a loop and a cron entry and the Monday-invoices chore runs itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./incoming
&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./converted
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IN&lt;/span&gt;&lt;span class="s2"&gt;/done"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.pdf&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.pdf&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  curl &lt;span class="nt"&gt;-fsS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://convertica.net/api/v1/pdf-to-excel/ &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.xlsx"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/done/"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# every Monday at 6am
0 6 * * 1 /home/me/scripts/convert-invoices.sh &amp;gt;&amp;gt; /var/log/convert.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;set -euo pipefail&lt;/code&gt; and &lt;code&gt;curl -fsS&lt;/code&gt; matter more than they look. Without them a failed conversion writes a zero-byte file, your &lt;code&gt;mv&lt;/code&gt; marks it done, and you lose the input silently. Fail loudly instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parts people skip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency.&lt;/strong&gt; Move processed files out of the input folder (or track them) so a re-run does not convert the same file twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scanned inputs.&lt;/strong&gt; If the batch might contain scans, expect OCR and add a sanity check on the output. A zero-length or suspiciously tiny result usually means a bad scan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleanup.&lt;/strong&gt; Whatever service you use, know its retention. Convertica deletes uploads from the server after a short window, which is what you want for statements and contracts rather than throwaway samples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets stay home.&lt;/strong&gt; For genuinely confidential documents I generate the file from source rather than round-tripping it through any external service, mine included. Automation is for the routine stuff, not the crown jewels.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Do not forget the passwords
&lt;/h2&gt;

&lt;p&gt;One thing that quietly breaks batch jobs: a password-protected PDF in the input. There are two kinds, and they fail differently. An owner-password file (restrictions only) usually still converts. An open-password file is encrypted and will not convert without the password, and no tool bypasses real encryption, so your script should catch that case and set the file aside for a human rather than retrying forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;The work has not changed. Files still need to be smaller, converted, and machine-readable. What changed is that the repetitive slice of it belongs in a five-line script and a cron entry. Spend the ten seconds to check text-versus-scan, fail loudly, respect retention, and the Monday chore stops being a chore.&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>automation</category>
      <category>api</category>
      <category>productivity</category>
    </item>
    <item>
      <title>PDF Chores You No Longer Need a Desktop App For</title>
      <dc:creator>Convertica</dc:creator>
      <pubDate>Tue, 14 Jul 2026 12:49:03 +0000</pubDate>
      <link>https://dev.to/convertica/pdf-chores-you-no-longer-need-a-desktop-app-for-602</link>
      <guid>https://dev.to/convertica/pdf-chores-you-no-longer-need-a-desktop-app-for-602</guid>
      <description>&lt;p&gt;Every few weeks a PDF lands on my desk that needs something done to it. Shrink it so an email will accept it. Pull a table into a spreadsheet. Merge four scans into one file. For years the reflex was to open a heavy desktop app, or worse, to pay for one just to run a two-minute task. That reflex is out of date. Almost all of it now runs in a browser tab, and some of it runs from a script.&lt;/p&gt;

&lt;p&gt;I want to walk through the ones I actually use, and where the line sits between "do it in the browser" and "automate it."&lt;/p&gt;

&lt;h2&gt;
  
  
  The one check that saves you every time
&lt;/h2&gt;

&lt;p&gt;Before touching any PDF tool, find out what kind of file you have. Select a word on the page. If it highlights, the text is real and any conversion will be clean. If nothing highlights, the page is an image (a scan), and you need OCR to get text out of it.&lt;/p&gt;

&lt;p&gt;This sounds trivial, but it explains most "the converter mangled my file" complaints. A native PDF converts faithfully. A scanned one goes through character recognition, which is good but not perfect, so you review the output. Knowing which you have sets your expectations correctly before you start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shrinking a PDF for email
&lt;/h2&gt;

&lt;p&gt;Mail providers still cap attachments low: Gmail at 25 MB, Outlook around 20, plenty of corporate servers at 10. A 300-DPI scan blows past all of them.&lt;/p&gt;

&lt;p&gt;Compression re-encodes the images inside the file while leaving the text sharp. Medium compression is the sweet spot for email: the file drops several times over and you will not see the difference on screen. Keep maximum quality only when the destination is a professional printer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting tables out of a PDF and into a spreadsheet
&lt;/h2&gt;

&lt;p&gt;This is the one that used to eat my afternoons. Copy-pasting a PDF table into a spreadsheet collapses it into a single column of run-together text, because a PDF stores text at fixed coordinates, not as a real grid. A proper conversion reads the position of every value and rebuilds actual cells, so numbers land under the right headers.&lt;/p&gt;

&lt;p&gt;For one-off files, a browser tool is the fastest path. When it becomes routine, say a nightly batch of statements, this is where automation earns its keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to reach for an API instead of a tab
&lt;/h2&gt;

&lt;p&gt;The browser is right for occasional work. But if you are converting the same kind of document on a schedule, or building a feature into your own app, you do not want a human clicking upload. That is the point where a free API pays off.&lt;/p&gt;

&lt;p&gt;I have been using &lt;a href="https://convertica.net/" rel="noopener noreferrer"&gt;Convertica&lt;/a&gt; for both sides of this. The web tools cover the ad-hoc jobs (compress, merge, split, PDF to Word or Excel, unlock, and so on) with no signup, and there is an API for wiring conversions into a pipeline. A typical call is nothing more than a POST with the file:&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://convertica.net/api/v1/pdf-to-word/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"file=@report.pdf"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; report.docx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uploaded files are removed from the server after a short window, which matters when the documents are statements or contracts rather than throwaway samples. For anything genuinely secret, I still generate the file from source rather than round-tripping it through any service, mine or otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on PDF passwords, since it trips people up
&lt;/h2&gt;

&lt;p&gt;PDFs carry two kinds of password and they behave very differently. An open password encrypts the file: without it, nothing can read the content, and no tool bypasses real encryption in seconds regardless of what its landing page claims. A permissions password only disables copy, print, or edit while letting the file open, and that kind was never strong protection to begin with.&lt;/p&gt;

&lt;p&gt;The practical takeaway for developers: if you need to actually secure a document, set an open password and share it out of band. Do not rely on permission flags, because most readers and libraries ignore them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shift, in one line
&lt;/h2&gt;

&lt;p&gt;The work has not changed. Files still need to be smaller, mergeable, and machine-readable. What changed is that none of it requires a paid desktop install anymore. Occasional jobs go in a browser tab, repeated ones go through an API, and the only real prerequisite is that ten-second check of whether your PDF is text or a picture.&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
