<?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: toolsvale</title>
    <description>The latest articles on DEV Community by toolsvale (@toolsvale).</description>
    <link>https://dev.to/toolsvale</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%2F4077234%2F4e245a3e-fcab-4773-8e13-cf7cafe4caa0.png</url>
      <title>DEV Community: toolsvale</title>
      <link>https://dev.to/toolsvale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/toolsvale"/>
    <language>en</language>
    <item>
      <title>I audited 12 free SEO tools. Here's what they all get wrong.</title>
      <dc:creator>toolsvale</dc:creator>
      <pubDate>Thu, 20 Aug 2026 22:01:50 +0000</pubDate>
      <link>https://dev.to/toolsvale/i-audited-12-free-seo-tools-heres-what-they-all-get-wrong-486</link>
      <guid>https://dev.to/toolsvale/i-audited-12-free-seo-tools-heres-what-they-all-get-wrong-486</guid>
      <description>&lt;p&gt;Last week I needed to audit a client site — check broken links, verify schema, sanity-check a sitemap, spot-check indexing on 40 URLs. Nothing exotic. I opened Google, typed the obvious queries, and clicked whatever ranked.&lt;/p&gt;

&lt;p&gt;Four hours later I had my report, but I also had a very long list of ways free SEO tools are quietly broken. Not "missing features" broken — actively misleading broken. This post is that list, because I ended up building &lt;a href="https://toolsvale.com" rel="noopener noreferrer"&gt;ToolsVale&lt;/a&gt; around the fixes and I think the pattern is worth writing down whether you build tools or just use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Twelve tools total, spread across the four jobs above: broken link checkers, schema validators, sitemap generators, indexing checkers. For each one I gave the same input a real site would give: 500 URLs for the link checker, a live JSON-LD block for the schema tool, an existing sitemap for the generator, 40 URLs for the indexing check.&lt;/p&gt;

&lt;p&gt;I noted every single thing that broke, gated, or gave me an answer I couldn't trust. I'm not naming names — this is about pattern, not takedown — but if you've used a free SEO tool recently you've hit at least four of these.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 8 patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The sign-up wall at result 5
&lt;/h3&gt;

&lt;p&gt;Every free broken link checker I tried let me check 3–10 URLs before demanding an account "to continue." Not for advanced features. To see result #6.&lt;/p&gt;

&lt;p&gt;The tools that do this are betting you're too invested to bounce. Sometimes they're right. Mostly you close the tab and try the next result.&lt;/p&gt;

&lt;p&gt;The fix: no auth. If the crawl runs in the browser (fetch + concurrent workers), there's no server cost to gate. Even server-side, a 500-URL crawl is measured in cents, not dollars.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Redirect chains flattened to final destination
&lt;/h3&gt;

&lt;p&gt;Nine of the twelve link checkers showed only the final URL in a redirect chain. So a URL that goes &lt;code&gt;/page → /page/ → /new-page/ → 404&lt;/code&gt; shows up as "404" with no indication of the two hops in between.&lt;/p&gt;

&lt;p&gt;This matters because &lt;em&gt;the redirect chain itself is the SEO problem&lt;/em&gt;. Each hop leaks link equity. A tool that hides the chain is hiding the actual work you need to do.&lt;/p&gt;

&lt;p&gt;The fix: show every hop, every status code, every URL, in order. Half a day of dev work.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. "Broken link" without the source page
&lt;/h3&gt;

&lt;p&gt;Most broken link tools tell you the URL is broken. Almost none tell you &lt;em&gt;which page on your site is still linking to it&lt;/em&gt;. So you have a 404, but you don't know what to edit to remove the link.&lt;/p&gt;

&lt;p&gt;If you don't have the source, you can't fix the cause — only the symptom (by 301-redirecting the broken URL somewhere, which just adds a redirect chain, see problem #2).&lt;/p&gt;

&lt;p&gt;The fix: during the crawl, store the referrer for every URL discovered. Trivially cheap. Nobody does it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Schema validators that accept garbage
&lt;/h3&gt;

&lt;p&gt;I fed a JSON-LD block to five free schema validators. Three of them said "valid" for a block that was missing required properties (&lt;code&gt;@context&lt;/code&gt;, &lt;code&gt;@type&lt;/code&gt;, and — in one case — a mandatory &lt;code&gt;datePublished&lt;/code&gt; for &lt;code&gt;Article&lt;/code&gt; schema).&lt;/p&gt;

&lt;p&gt;They're technically running through a JSON linter, not a schema.org validator. But they're called "schema validators" and users assume the check means something.&lt;/p&gt;

&lt;p&gt;Google's own Rich Results Test catches these. Free third-party tools mostly don't.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Sitemap generators that ignore rules
&lt;/h3&gt;

&lt;p&gt;The sitemap.xml spec has real constraints: 50MB max file size, 50,000 URLs max per file, index files needed above that. Three of the four sitemap generators I tried produced a single flat file for a 65,000-URL input, in violation of the spec, and Google will reject it on ingestion.&lt;/p&gt;

&lt;p&gt;The fix: split into &lt;code&gt;sitemap-1.xml&lt;/code&gt;, &lt;code&gt;sitemap-2.xml&lt;/code&gt;, etc., with an index. It's a while-loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Cached results shown as live
&lt;/h3&gt;

&lt;p&gt;Two of the three indexing checkers I tested returned results in &amp;lt;100ms for a URL that had been published five minutes earlier. That's not a live check — that's a cached snapshot from days or weeks ago.&lt;/p&gt;

&lt;p&gt;The tools don't say this. They just show a green "indexed" checkmark for a URL that Google has never seen.&lt;/p&gt;

&lt;p&gt;The fix: either do a real live check (&lt;code&gt;site:&lt;/code&gt; query, respecting rate limits), or clearly label the data source and age. Users can handle "cached from 3 days ago." They can't handle "green tick, in reality Google 404's your URL."&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Robots.txt as an afterthought
&lt;/h3&gt;

&lt;p&gt;Half the free crawlers I tested happily crawled &lt;code&gt;/wp-admin/&lt;/code&gt;, &lt;code&gt;/checkout/&lt;/code&gt;, &lt;code&gt;/cart/&lt;/code&gt;, and anything else &lt;code&gt;robots.txt&lt;/code&gt; would have disallowed a well-behaved crawler from touching. Some of these paths return sensitive data if you're logged in — which the tool won't be, but the point is a tool that doesn't respect &lt;code&gt;robots.txt&lt;/code&gt; isn't a serious tool.&lt;/p&gt;

&lt;p&gt;The fix: fetch and parse &lt;code&gt;robots.txt&lt;/code&gt; before crawl, honor &lt;code&gt;Disallow&lt;/code&gt; for &lt;code&gt;User-agent: *&lt;/code&gt; at minimum. Small library away.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Hreflang tools without x-default
&lt;/h3&gt;

&lt;p&gt;Free hreflang generators universally forget the &lt;code&gt;x-default&lt;/code&gt; value. &lt;code&gt;x-default&lt;/code&gt; is what Google uses when the visitor's language doesn't match any of the declared alternates. Skip it and you're telling Google "if the user speaks Portuguese and my site is only in English/Spanish/French, I have no opinion" — which becomes a soft-signal ranking issue.&lt;/p&gt;

&lt;p&gt;Every generator I tried was missing this. Fix: add one more form field with a plain-English label ("Which language should show when nothing else matches?"). Ten minutes of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it like this?
&lt;/h2&gt;

&lt;p&gt;I don't think most of these SEO tools ship broken defaults out of malice. I think they ship as MVPs — a wrapper around a Python script or the Google Custom Search API, monetized with ads, then forgotten. The gaps aren't bugs to fix, they're features that would eat the paid tier or expose that the "free" checker is actually a lead magnet.&lt;/p&gt;

&lt;p&gt;Which means the space is enormous, the incumbents are entrenched by SEO not quality (yes, SEO tools ranking on SEO — the irony writes itself), and it's genuinely open to anyone who ships a version that doesn't have these problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I ended up building &lt;a href="https://toolsvale.com" rel="noopener noreferrer"&gt;ToolsVale&lt;/a&gt; — free browser-based tools for images, PDFs, data and SEO, currently 38 of them. The rule is: before any tool goes live, we run the same input through the popular alternatives and note where the output breaks. Those notes become the spec. Every claim on a tool page comes with a test you can run in under a minute.&lt;/p&gt;

&lt;p&gt;A few examples for anyone curious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://toolsvale.com/bulk-url-status-code-checker/" rel="noopener noreferrer"&gt;bulk URL status code checker&lt;/a&gt;&lt;/strong&gt; — 500 URLs, full redirect chains shown, soft-404 detection, response times, and headers. Fixes problems #1 and #2 above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://toolsvale.com/best-broken-link-checker/" rel="noopener noreferrer"&gt;broken link checker&lt;/a&gt;&lt;/strong&gt; — bulk broken link scanner that stores the source page for every broken URL, not just the destination. Fixes problem #3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://toolsvale.com/trailing-slash-checker/" rel="noopener noreferrer"&gt;trailing slash checker&lt;/a&gt;&lt;/strong&gt; — finds URLs redirecting only because of a missing or extra slash, and traces back to the source page still linking to the wrong version. This is problem #3 applied to a very specific SEO gotcha.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://toolsvale.com/schema-markup-generator/" rel="noopener noreferrer"&gt;schema markup generator&lt;/a&gt;&lt;/strong&gt; — outputs schema that actually passes Google's Rich Results Test, not just JSON lint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://toolsvale.com/hreflang-tag-generator/" rel="noopener noreferrer"&gt;hreflang generator&lt;/a&gt;&lt;/strong&gt; — includes &lt;code&gt;x-default&lt;/code&gt; by default because that's the correct answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most tools run entirely in the browser. The ones that need a server (like bulk URL checking, which can't be done purely client-side due to CORS) say so on the tool card with a stated deletion window.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway if you're not building tools
&lt;/h2&gt;

&lt;p&gt;If you're just picking an SEO tool for a task, three things to check before you rely on any result:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Give it a URL you know has a redirect chain (any &lt;code&gt;http://&lt;/code&gt; URL that ends up on &lt;code&gt;https://&lt;/code&gt; with a trailing slash works). Does it show all hops, or only the final destination?&lt;/li&gt;
&lt;li&gt;Give the schema validator a JSON-LD block with a deliberately missing required field. Does it catch it, or does it happily pass?&lt;/li&gt;
&lt;li&gt;Check whether the indexing checker returns instantly (&amp;lt;200ms). If yes, it's cached data, not a live check.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're building one, the good news is the bar is astonishingly low. Almost every "premium" feature these sites gate is a while-loop, a spec-compliance check, or storing one extra field during crawl.&lt;/p&gt;

&lt;p&gt;The gap isn't technical. It's positioning. Anyone who ships the honest version wins.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Full tool set at &lt;a href="https://toolsvale.com" rel="noopener noreferrer"&gt;toolsvale.com&lt;/a&gt; — free, no accounts, no watermarks, most run in your browser. Open source components at &lt;a href="https://github.com/toolsvalewebsite" rel="noopener noreferrer"&gt;github.com/toolsvalewebsite&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you build in this space and want to compare notes on the browser-only approach, I'm on &lt;a href="https://x.com/toolsvale_web" rel="noopener noreferrer"&gt;X @toolsvale_web&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I created "Absolute Best" Broken link checker</title>
      <dc:creator>toolsvale</dc:creator>
      <pubDate>Wed, 19 Aug 2026 21:14:32 +0000</pubDate>
      <link>https://dev.to/toolsvale/i-created-absolute-best-broken-link-checker-2ffj</link>
      <guid>https://dev.to/toolsvale/i-created-absolute-best-broken-link-checker-2ffj</guid>
      <description>&lt;h2&gt;
  
  
  Quick Website Check
&lt;/h2&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%2F7v4zgc6jz7vjjiroeqz6.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%2F7v4zgc6jz7vjjiroeqz6.png" alt=" " width="335" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Broken links are easy to miss on larger websites.&lt;/li&gt;
&lt;li&gt;A 404 can come from deleted pages, changed URLs, bad redirects, or external sites going offline.&lt;/li&gt;
&lt;li&gt;I’ve been using a simple free tool to crawl a website and find broken links.&lt;/li&gt;
&lt;li&gt;It also shows &lt;strong&gt;exactly which page contains the broken link&lt;/strong&gt;, not just the dead URL.&lt;/li&gt;
&lt;li&gt;It supports internal + external links and lets you export the results.&lt;/li&gt;
&lt;li&gt;No signup required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;a href="https://toolsvale.com/broken-link-checker/" rel="noopener noreferrer"&gt;https://toolsvale.com/broken-link-checker/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Useful for developers, SEO audits, migrations, and website maintenance.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Built an Image Converter That Never Touches a Server</title>
      <dc:creator>toolsvale</dc:creator>
      <pubDate>Fri, 14 Aug 2026 07:15:39 +0000</pubDate>
      <link>https://dev.to/toolsvale/how-i-built-an-image-converter-that-never-touches-a-server-27i</link>
      <guid>https://dev.to/toolsvale/how-i-built-an-image-converter-that-never-touches-a-server-27i</guid>
      <description>&lt;p&gt;How I Built an Image Converter That Never Touches a Server&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://toolsvale.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftoolsvale.com%2Fwp-content%2Fuploads%2F2026%2F08%2FToolsVale.webp" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://toolsvale.com/" rel="noopener noreferrer" class="c-link"&gt;
            Home - ToolsVale
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftoolsvale.com%2Fwp-content%2Fuploads%2F2026%2F08%2Ffavicon.webp" width="96" height="96"&gt;
          toolsvale.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Most "free online image converter" sites work the same way under the hood: your file gets POSTed to an endpoint, a server does the actual conversion, and you get a download link back. That's normal and fine for a lot of use cases — but it means every file you convert briefly exists on infrastructure you don't control, and it means the tool needs a backend, storage, cleanup jobs, and rate limits just to exist.&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%2Fotjv8y6i65usubv4ng75.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fotjv8y6i65usubv4ng75.jpg" alt=" " width="800" height="795"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to see if I could skip all of that and do the conversion entirely in the browser instead. Turns out modern browser APIs make this pretty viable. Here's roughly how it works.&lt;/p&gt;

&lt;p&gt;The core idea: Canvas as a conversion engine&lt;/p&gt;

&lt;p&gt;The browser's  element can decode most image formats it can display, and re-encode them via canvas.toBlob() or canvas.toDataURL() with a different MIME type. So a JPG → WebP conversion is roughly:&lt;/p&gt;

&lt;p&gt;async function convertImage(file, outputType = 'image/webp', quality = 0.8) {&lt;br&gt;
  const bitmap = await createImageBitmap(file);&lt;br&gt;
  const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);&lt;br&gt;
  const ctx = canvas.getContext('2d');&lt;br&gt;
  ctx.drawImage(bitmap, 0, 0);&lt;br&gt;
  const blob = await canvas.convertToBlob({ type: outputType, quality });&lt;br&gt;
  return blob;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;createImageBitmap handles the decode off the main thread, OffscreenCanvas lets you do this inside a Web Worker (important — you don't want to block the UI on a 40-image batch), and convertToBlob handles re-encoding. No network request anywhere in that flow.&lt;/p&gt;

&lt;p&gt;Where it gets harder: formats the browser can't natively decode&lt;/p&gt;

&lt;p&gt;Canvas only helps for formats the browser already knows how to render. HEIC is the obvious problem — no mainstream browser decodes HEIC natively, since it's patent-encumbered and Apple-specific. For that, you need a WASM-compiled decoder (libheif compiled to WASM works) running client-side, which decodes HEIC into raw pixel data the canvas can then take over from. Same category of problem for AVIF on older browser versions, though support there is improving fast.&lt;/p&gt;

&lt;p&gt;The general pattern: whatever the browser can decode natively, let it. Whatever it can't, ship a WASM decoder for. This keeps the bundle smaller than compiling everything to WASM, since you're only covering the gaps.&lt;/p&gt;

&lt;p&gt;The trade-offs, honestly&lt;br&gt;
Performance is your user's device, not yours. A batch of 200 large images on a low-end laptop will be slow. There's no way around this — you're trading server cost for user CPU time. For most day-to-day batch sizes it's a non-issue, but it's not free.&lt;br&gt;
No persistence. Nothing's stored anywhere, which is the whole point, but it also means there's no "history" or account-based re-download. Close the tab before saving and it's gone.&lt;br&gt;
Web Workers are non-negotiable for batches. Running conversion on the main thread freezes the UI on anything more than a couple of files. OffscreenCanvas + Workers is what makes multi-file drag-and-drop feel responsive instead of janky.&lt;br&gt;
Memory matters more than you'd think. Holding decoded bitmaps for dozens of large images in memory simultaneously adds up fast — worth converting and releasing one at a time rather than decoding everything upfront.&lt;br&gt;
Why bother, when server-side is simpler to build&lt;/p&gt;

&lt;p&gt;Two reasons I found compelling enough to go this route:&lt;/p&gt;

&lt;p&gt;No file-size or file-count caps to justify. Server-side tools cap free usage because storage and bandwidth cost money. Client-side has no such constraint — the only limit is the user's own machine.&lt;br&gt;
It's verifiable, not just claimed. "We don't store your files" is a common claim on converter sites, but users can't check it. With client-side processing, anyone can open the network tab or go offline mid-conversion and see for themselves that nothing left the device.&lt;/p&gt;

&lt;p&gt;I ended up building this out into a small set of tools — ToolsVale — covering the common image conversion pairs (JPG/PNG/HEIC/AVIF ↔ WebP), image-to-PDF, and compression, all running on this pattern.&lt;/p&gt;

&lt;p&gt;Curious if anyone else here has shipped something similar — particularly interested in how others have handled HEIC decode performance, since that's been the trickiest part so far.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
