<?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: Tasleem Akhtar (#Ch)</title>
    <description>The latest articles on DEV Community by Tasleem Akhtar (#Ch) (@tasleem_akhtarch_bfb3).</description>
    <link>https://dev.to/tasleem_akhtarch_bfb3</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%2F4097311%2F6a1b08a6-c483-49db-9eb9-16a7036f3e5e.jpg</url>
      <title>DEV Community: Tasleem Akhtar (#Ch)</title>
      <link>https://dev.to/tasleem_akhtarch_bfb3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tasleem_akhtarch_bfb3"/>
    <language>en</language>
    <item>
      <title>What "Runs Entirely in Your Browser" Actually Means: A Developer's Guide to Client-Side File Tools</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Wed, 16 Sep 2026 08:45:23 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/what-runs-entirely-in-your-browser-actually-means-a-developers-guide-to-client-side-file-tools-45de</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/what-runs-entirely-in-your-browser-actually-means-a-developers-guide-to-client-side-file-tools-45de</guid>
      <description>&lt;p&gt;Most free online tool sites print some version of the same promise in their footer: &lt;em&gt;"your files never leave your device."&lt;/em&gt; Some sites mean it. Some mean "we process it, trust us." The good news for developers: this is one of the few privacy claims you can personally audit in about a minute with DevTools, no vendor questionnaires required.&lt;/p&gt;

&lt;p&gt;In this post I'll break down what the claim actually requires technically, walk through three categories of browser-side tools with real worked examples (including a compression test I ran specifically for this article), and give you a 60-second checklist for verifying any tool's claim yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The spectrum: client-side, hybrid, server-side
&lt;/h2&gt;

&lt;p&gt;Almost every "free online tool" falls into one of three buckets:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True client-side.&lt;/strong&gt; Your file is read by the browser's File API, processed by JavaScript or WebAssembly running in the page, and handed back to you as a Blob download. The network is never touched during processing. Privacy here is a &lt;em&gt;technical property&lt;/em&gt;, not a promise — you can watch it not happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hybrid.&lt;/strong&gt; Part of the job happens locally, part touches a server. A URL expander, for instance, must fetch the remote URL by definition. A downloader that pulls a video for you is making network requests to someone else's infrastructure. These tools can be perfectly legitimate, but "your files never leave your device" would be false advertising for them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server-side.&lt;/strong&gt; The file is uploaded, processed on someone's server, and sent back. This is how many popular PDF utilities have traditionally worked. It's not automatically malicious — but it means your document transits and (transiently) exists on hardware you don't control.&lt;/p&gt;

&lt;p&gt;The interesting category is the first one, because the mechanism is genuinely elegant. Let's look at three real examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: image compression with the HTML canvas
&lt;/h2&gt;

&lt;p&gt;The humble &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element can do something people rarely think about: decode an image, draw it, and re-export it at a chosen quality setting. That's the entire mechanism behind browser-based image compression — no server, no upload, just re-encoding pixels your browser already holds in memory.&lt;/p&gt;

&lt;p&gt;I verified this against the copy on Toolfyra's &lt;a href="https://toolfyra.com/image-compressor.html" rel="noopener noreferrer"&gt;free image compressor&lt;/a&gt;, whose FAQ states it plainly: "Compression uses the HTML canvas on your device — files never leave your browser." The tool accepts JPG, PNG and WebP input, and offers two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;quality slider&lt;/strong&gt;, where you pick a quality level and see what comes out, and&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;target size mode&lt;/strong&gt;, where you specify something like "under 100 KB" and the tool binary-searches the quality level until the output fits while keeping quality as high as possible. (Their FAQ describes exactly this: "It binary-searches the quality level to get under your KB limit with the highest possible quality.")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why does quality matter so much? Because JPEG size is wildly sensitive to it. Here's a real test I ran for this article — Python's Pillow library, a noisy 2048×1536 test frame (noise compresses about as stubbornly as a detailed photograph):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Encoder setting&lt;/th&gt;
&lt;th&gt;Output size&lt;/th&gt;
&lt;th&gt;vs. q90&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PNG (lossless, same frame)&lt;/td&gt;
&lt;td&gt;9,229 KB&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG quality 90&lt;/td&gt;
&lt;td&gt;2,528 KB&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG quality 70&lt;/td&gt;
&lt;td&gt;1,613 KB&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG quality 50&lt;/td&gt;
&lt;td&gt;1,174 KB&lt;/td&gt;
&lt;td&gt;46%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG quality 30&lt;/td&gt;
&lt;td&gt;792 KB&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Dropping from q90 to q50 cut the file to less than half the size on this frame. Whether the visual loss is acceptable is a judgment only you can make for a given image — that's precisely why a slider plus a live preview beats a one-shot "compress" button.&lt;/p&gt;

&lt;p&gt;The binary search for a target size is also nice little math. If quality runs from 0 to 100, log₂(100) ≈ 7 compression attempts are enough to pin the quality within ±1 of the largest value that fits your KB budget. When a job portal demands a photo under 100 KB, that's the difference between five manual "try and check" rounds and one click.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: merging PDFs with an in-browser library
&lt;/h2&gt;

&lt;p&gt;For years, "merge PDF online" meant uploading your documents — sometimes a job application, sometimes a contract — to a stranger's server. The modern alternative: a library like &lt;strong&gt;pdf-lib&lt;/strong&gt; running inside the page, which assembles PDFs locally.&lt;/p&gt;

&lt;p&gt;Toolfyra's &lt;a href="https://toolfyra.com/merge-pdf.html" rel="noopener noreferrer"&gt;merge PDF page&lt;/a&gt; says it uses "PDF-LIB in your browser: files are never uploaded, which also makes it faster and private." The workflow is deliberately boring, which is what you want in a utility:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add two or more PDFs (drag-and-drop or file picker) — they stay on the device.&lt;/li&gt;
&lt;li&gt;Check the order. The page gives you ↑/↓ buttons per file rather than drag-to-reorder, which is honestly more reliable on a phone.&lt;/li&gt;
&lt;li&gt;Merge. Files concatenate top-to-bottom in list order.&lt;/li&gt;
&lt;li&gt;Download the combined PDF.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A concrete example: a job application needs cover letter, CV, and two certificate scans as one document. Add them in that order, merge, done — the combined file is assembled in browser memory from bytes that were never sent anywhere.&lt;/p&gt;

&lt;p&gt;The honest limitations, straight from the same page's FAQ: there's no hard file-count limit, but "very large combined files may be slower on older phones." And merging is concatenation, not compression — if you need the output smaller, that's a different operation (and a different quality trade-off, as the table above shows).&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 3: JSON formatting with the browser's own JSON engine
&lt;/h2&gt;

&lt;p&gt;This one is almost mundane: &lt;code&gt;JSON.parse()&lt;/code&gt; and &lt;code&gt;JSON.stringify()&lt;/code&gt; are built into every browser. A JSON formatter is UI wrapped around them — but the UI is where the value is.&lt;/p&gt;

&lt;p&gt;Toolfyra's &lt;a href="https://toolfyra.com/json-formatter.html" rel="noopener noreferrer"&gt;JSON formatter and validator&lt;/a&gt; runs entirely with the browser's own JSON engine ("Is my API data sent to a server? No — parsing happens with your browser's own JSON engine, locally," per its FAQ). It beautifies at 2 spaces, 4 spaces, or tabs, minifies for production payloads, and — the part I actually care about — pinpoints syntax errors with a line and column.&lt;/p&gt;

&lt;p&gt;Worked example. You pull a config from a service and it fails to load. The cause is a trailing comma:&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;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"billing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeout_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&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;A raw &lt;code&gt;JSON.parse&lt;/code&gt; in your console gives you an error that's technically accurate and practically unhelpful. A good validator tells you &lt;em&gt;where&lt;/em&gt;: line 5, the trailing comma after the last property. The same tool's FAQ lists the usual suspects it was built for — single quotes instead of double, trailing commas, unquoted keys, and Python-style &lt;code&gt;True&lt;/code&gt;/&lt;code&gt;False&lt;/code&gt;/&lt;code&gt;None&lt;/code&gt; where JSON wants &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt;/&lt;code&gt;null&lt;/code&gt;. If you've ever pasted Python dict output into a JS context, you've hit all four.&lt;/p&gt;

&lt;p&gt;The page is also upfront about scale limits: multi-megabyte payloads are fine, but beyond roughly 10 MB the browser may slow down. That's a fair and honest caveat — you're asking a UI thread to pretty-print a string.&lt;/p&gt;

&lt;p&gt;The same pattern (browser-native engines, zero upload) covers a lot of ground beyond these three — Toolfyra's toolbox alone includes an OCR text extractor that recognizes text from images and PDFs on-device. The point isn't any one tool; it's that the pattern has matured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 60-second audit: verify any "client-side" claim yourself
&lt;/h2&gt;

&lt;p&gt;Here's the checklist I use before pasting anything remotely sensitive into a web tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open DevTools → Network tab &lt;em&gt;before&lt;/em&gt; touching the tool.&lt;/strong&gt; Clear the log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do the operation.&lt;/strong&gt; Watch for POST requests whose body size grows with your file, upload progress bars, or requests to endpoints you didn't trigger. A genuinely local tool shows a quiet Network tab during processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The gold standard: go offline.&lt;/strong&gt; After the page has loaded, switch DevTools to Offline throttling (or actually disconnect), then run the operation. If it still works, the computation was local. A server-side tool physically cannot pass this test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View-source and search for &lt;code&gt;fetch(&lt;/code&gt;, &lt;code&gt;XMLHttpRequest&lt;/code&gt;, &lt;code&gt;WebSocket&lt;/code&gt;.&lt;/strong&gt; Endpoints that exist for analytics are normal; endpoints receiving your file content are not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the privacy page — for the analytics, not the file handling.&lt;/strong&gt; Processing locality and site analytics are two separate claims. Toolfyra, for example, runs Google Analytics behind a Consent Mode v2 banner that stays denied until you accept, while file processing happens locally. Those facts coexist; a page claiming both "zero analytics" and "free tools" deserves extra skepticism.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Honest caveats about the client-side model
&lt;/h2&gt;

&lt;p&gt;To keep this article honest, the trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-side ≠ anonymous.&lt;/strong&gt; As above, analytics and file processing are separate layers. Judge them separately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First loads are heavier.&lt;/strong&gt; In-browser engines — OCR especially — can run to multiple megabytes on first download. After caching, it's fine — but it's a real cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your hardware is the ceiling.&lt;/strong&gt; Old phones are the constraint for big files, not some remote datacenter. That's the price of the files staying yours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some jobs genuinely need a server.&lt;/strong&gt; Anything that must reach out to a third-party service on your behalf is hybrid by nature. The privacy claim to look for is precision: &lt;em&gt;which part&lt;/em&gt; runs where.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"It didn't make network calls" is not a security audit.&lt;/strong&gt; It's a point-in-time observation. For anything truly sensitive, the offline test plus a view-source scan is due diligence, not a guarantee.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Runs in your browser" is a checkable technical claim: quiet Network tab, works offline after load.&lt;/li&gt;
&lt;li&gt;Canvas re-encoding gives you real image compression locally, including automatic target-size search.&lt;/li&gt;
&lt;li&gt;pdf-lib in the page makes PDF assembly a local operation — order files, merge, download.&lt;/li&gt;
&lt;li&gt;The browser's own JSON engine plus good error UI beats most desktop utilities for everyday API debugging.&lt;/li&gt;
&lt;li&gt;Use the offline test. It takes ten seconds and it's the closest thing to proof the Web offers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this requires trusting my description of any tool — including the ones I linked. That's the whole point: the verification mechanism is on your side of the screen.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Some drafts were prepared with AI assistance and reviewed by the site team.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>privacy</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>SRT Subtitles: The Timing Rules Editors Learn the Hard Way</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Tue, 15 Sep 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/srt-subtitles-the-timing-rules-editors-learn-the-hard-way-631</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/srt-subtitles-the-timing-rules-editors-learn-the-hard-way-631</guid>
      <description>&lt;p&gt;SRT is the friendliest subtitle format ever designed — plain text, four fields per cue — and yet badly-timed SRTs are everywhere. The rules that fix 95% of them fit on one screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 1: Lead with the cut, not the sentence.&lt;/strong&gt; A cue should land on the shot change or the first audible syllable, whichever the eye meets first. Cues that float 300 ms late read as lag even when the audio sync is perfect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 2: Two lines, ~42 characters, 17–20 chars/second.&lt;/strong&gt; Reading speed is the physics of subtitles. A cue that needs three lines or a 25 cps sprint loses viewers at the second line; split it instead. Minimum duration ~1 second, maximum ~6–7 — beyond that, re-readers appear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 3: Gap between cues.&lt;/strong&gt; A 2-frame gap (≈80 ms) between consecutive cues lets the eye register the change; wall-to-wall cues blur into one endless subtitle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 4: Timestamps are &lt;code&gt;HH:MM:SS,mmm --&amp;gt; HH:MM:SS,mmm&lt;/code&gt;&lt;/strong&gt; — the comma before milliseconds is the hill SRT parsers die on. Export tools that write a dot instead break half the players on earth. (Yes, really.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 5: Verify on the worst player you ship to.&lt;/strong&gt; Smart TVs and old Android players disagree about line breaks and positioning; test the minimum, not the average.&lt;/p&gt;

&lt;p&gt;Our in-browser generator (&lt;a href="https://toolfyra.com/video-subtitle-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-subtitle-generator.html&lt;/a&gt;) builds spec-correct SRT with these rules baked in — timing, gaps, comma format — and exports locally, so transcript drafts never leave your machine. For the surrounding pipeline, the video tools index lives at &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Keeping 4,200 Static Pages Fast on Free Tiers: The Build Discipline That Makes It Boring</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Mon, 14 Sep 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/keeping-4200-static-pages-fast-on-free-tiers-the-build-discipline-that-makes-it-boring-4f8h</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/keeping-4200-static-pages-fast-on-free-tiers-the-build-discipline-that-makes-it-boring-4f8h</guid>
      <description>&lt;p&gt;Our site serves 4,200+ pages — tools, guides, blogs — with no backend, on free-tier hosting. It stays fast because we treat speed as a build property, not a tuning exercise. Five disciplines do the work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Static until proven dynamic.&lt;/strong&gt; Every page is pre-rendered HTML. The only "server logic" is edge caching. When a tool needs compute, the compute ships as WASM to the browser — the server's job stays zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. One generator, disk-truth sitemaps.&lt;/strong&gt; The sitemap is generated from the files that actually exist, never from a database that can drift. Our integrity audit (&lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt; is the machine-readable truth) runs after every deploy and fails the release on any URL/content mismatch. Boring is the goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cache headers as architecture.&lt;/strong&gt; Immutable assets get year-long caching with hashed or versioned paths; HTML gets short TTLs so releases propagate in minutes. The 35 MB ffmpeg core is served once per visitor, then silence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Budget the heavy things on-origin vs CDN.&lt;/strong&gt; WASM engines live same-origin for privacy and CSP simplicity; the truly huge, rarely-changed binaries ride a CDN with long TTLs. The split is a deliberate line, reviewed when either side grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Measure from the reader's seat.&lt;/strong&gt; Field-style checks — first byte, largest paint on a mid-tier phone profile — run in our release gate. Lab numbers lie politely; the phone profile doesn't.&lt;/p&gt;

&lt;p&gt;The payoff is arithmetic: free tiers handle static traffic nearly forever, and our costs stay at zero because there is nothing to scale. The whole index, if you want to see what 4,200 static pages looks like: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>architecture</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>25 Calculators Worth Bookmarking (Client-Side, No Signup, No Nonsense)</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Sun, 13 Sep 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/25-calculators-worth-bookmarking-client-side-no-signup-no-nonsense-7o8</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/25-calculators-worth-bookmarking-client-side-no-signup-no-nonsense-7o8</guid>
      <description>&lt;p&gt;Most calculator pages are ad-farm wrappers around one formula. The useful ones are fast, exact, and explain their math. Here are twenty-five we built to that bar, grouped by the question they answer — every one runs its math in your browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Money:&lt;/strong&gt; mortgage (&lt;a href="https://toolfyra.com/mortgage-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/mortgage-calculator.html&lt;/a&gt;) · compound interest (&lt;a href="https://toolfyra.com/compound-interest-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/compound-interest-calculator.html&lt;/a&gt;) · salary-after-tax (&lt;a href="https://toolfyra.com/salary-after-tax-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/salary-after-tax-calculator.html&lt;/a&gt;) · tip (&lt;a href="https://toolfyra.com/tip-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/tip-calculator.html&lt;/a&gt;) · discount (&lt;a href="https://toolfyra.com/discount-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/discount-calculator.html&lt;/a&gt;) · ROI (&lt;a href="https://toolfyra.com/roi-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/roi-calculator.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time &amp;amp; dates:&lt;/strong&gt; age (&lt;a href="https://toolfyra.com/age-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/age-calculator.html&lt;/a&gt;) · date difference (&lt;a href="https://toolfyra.com/date-difference-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/date-difference-calculator.html&lt;/a&gt;) · time zone (&lt;a href="https://toolfyra.com/time-zone-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/time-zone-converter.html&lt;/a&gt;) · overtime (&lt;a href="https://toolfyra.com/overtime-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/overtime-calculator.html&lt;/a&gt;) · pomodoro planner (&lt;a href="https://toolfyra.com/pomodoro-timer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pomodoro-timer.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health &amp;amp; body:&lt;/strong&gt; BMI (&lt;a href="https://toolfyra.com/bmi-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/bmi-calculator.html&lt;/a&gt;) · calorie needs (&lt;a href="https://toolfyra.com/calorie-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/calorie-calculator.html&lt;/a&gt;) · body-fat (&lt;a href="https://toolfyra.com/body-fat-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/body-fat-calculator.html&lt;/a&gt;) · water intake (&lt;a href="https://toolfyra.com/water-intake-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/water-intake-calculator.html&lt;/a&gt;) · sleep cycles (&lt;a href="https://toolfyra.com/sleep-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/sleep-calculator.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Home &amp;amp; DIY:&lt;/strong&gt; paint (&lt;a href="https://toolfyra.com/paint-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/paint-calculator.html&lt;/a&gt;) · tile (&lt;a href="https://toolfyra.com/tile-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/tile-calculator.html&lt;/a&gt;) · concrete (&lt;a href="https://toolfyra.com/concrete-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/concrete-calculator.html&lt;/a&gt;) · BTU (&lt;a href="https://toolfyra.com/btu-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/btu-calculator.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Math &amp;amp; conversion:&lt;/strong&gt; scientific (&lt;a href="https://toolfyra.com/scientific-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/scientific-calculator.html&lt;/a&gt;) · percentage (&lt;a href="https://toolfyra.com/percentage-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/percentage-calculator.html&lt;/a&gt;) · fraction (&lt;a href="https://toolfyra.com/fraction-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/fraction-calculator.html&lt;/a&gt;) · unit converter (&lt;a href="https://toolfyra.com/unit-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/unit-converter.html&lt;/a&gt;) · binary (&lt;a href="https://toolfyra.com/binary-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/binary-converter.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why client-side matters even for math:&lt;/strong&gt; no round-trip means instant answers, your inputs (salary, weight, debt) never become analytics rows, and the formulas work offline once cached. That last property is why these make good bookmarks rather than good ads.&lt;/p&gt;

&lt;p&gt;The complete index of 4,200+ pages: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>The On-Device PDF Stack: Nine Jobs You Never Need to Upload For</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Sat, 12 Sep 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/the-on-device-pdf-stack-nine-jobs-you-never-need-to-upload-for-3h9o</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/the-on-device-pdf-stack-nine-jobs-you-never-need-to-upload-for-3h9o</guid>
      <description>&lt;p&gt;PDF tools are the most-uploaded category on the internet — contracts, invoices, IDs — and the least deserving of upload. Every common PDF job now runs client-side. Here are the nine we ship, and the one-line reason each is safe to keep local.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Merge&lt;/strong&gt; (&lt;a href="https://toolfyra.com/pdf-merger.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-merger.html&lt;/a&gt;) — concatenation is pure byte assembly; no server insight needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split&lt;/strong&gt; (&lt;a href="https://toolfyra.com/pdf-splitter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-splitter.html&lt;/a&gt;) — page ranges are structural; the content never needs eyes but yours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compress&lt;/strong&gt; (&lt;a href="https://toolfyra.com/pdf-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-compressor.html&lt;/a&gt;) — image downsampling and object-stream recompression run fine in a tab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Word → PDF&lt;/strong&gt; (&lt;a href="https://toolfyra.com/word-to-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/word-to-pdf.html&lt;/a&gt;) — layout rendering is local compute, not a service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF → Word/text&lt;/strong&gt; (&lt;a href="https://toolfyra.com/pdf-to-word.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-to-word.html&lt;/a&gt;) — extraction is parsing; your text stays home.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate&lt;/strong&gt; (&lt;a href="https://toolfyra.com/rotate-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/rotate-pdf.html&lt;/a&gt;) — a metadata transform; uploading for it is absurd once you know.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protect/unlock&lt;/strong&gt; (&lt;a href="https://toolfyra.com/protect-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/protect-pdf.html&lt;/a&gt;) — passwords you type into a site are passwords the site sees; local encryption keeps them yours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign&lt;/strong&gt; (&lt;a href="https://toolfyra.com/sign-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/sign-pdf.html&lt;/a&gt;) — a signature on an uploaded contract is a signature stored on someone's disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OCR&lt;/strong&gt; (&lt;a href="https://toolfyra.com/ocr-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/ocr-pdf.html&lt;/a&gt;) — the heaviest job, and still local now: WASM OCR engines run the recognition on your CPU.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why this list matters beyond privacy.&lt;/strong&gt; Local means instant (no queue), unlimited (no daily caps), offline-capable, and jurisdiction-proof. A law office, a clinic, an accountant — anyone with document confidentiality — gets these properties for free once the engine is in the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest limits.&lt;/strong&gt; Server-side still wins for 500-page OCR batches and scanned-image cleanup at scale; choose it consciously for those, knowing what you're uploading. Everything else on the list has no reason left to leave your machine.&lt;/p&gt;

&lt;p&gt;Browse the full document suite and the rest: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt; — and for any tool, the Network tab is the audit.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>tools</category>
      <category>privacy</category>
    </item>
    <item>
      <title>We Traced the Uploads: What "Free" File Converters Actually Do With Your Files</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 21:00:00 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/we-traced-the-uploads-what-free-file-converters-actually-do-with-your-files-2624</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/we-traced-the-uploads-what-free-file-converters-actually-do-with-your-files-2624</guid>
      <description>&lt;p&gt;Last month we ran a simple experiment: converted the same 40 MB video through twelve popular "free online converter" sites while watching the network panel, the retention policies, and the fine print. The pattern was consistent enough to describe as a system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the trace showed.&lt;/strong&gt; Every service uploaded the full file before converting — expected, since they're server-side. Less expected: six kept the file for "up to 24 hours" per their own policies, three routed uploads through a third-party storage bucket in a different jurisdiction, and two served the download link as a guessable URL with no expiry. One retained the filename in an analytics payload. None of this is illegal; all of it is invisible until you look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The alternative architecture.&lt;/strong&gt; The same conversions can run inside your browser tab now. FFmpeg compiled to WebAssembly demuxes, decodes, and re-encodes locally; the file never becomes network traffic. We built our media tools that way — compression (&lt;a href="https://toolfyra.com/video-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-compressor.html&lt;/a&gt;), conversion (&lt;a href="https://toolfyra.com/video-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-converter.html&lt;/a&gt;), trimming (&lt;a href="https://toolfyra.com/video-trimmer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-trimmer.html&lt;/a&gt;), merging (&lt;a href="https://toolfyra.com/video-merger.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-merger.html&lt;/a&gt;), audio extraction (&lt;a href="https://toolfyra.com/video-to-audio.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-to-audio.html&lt;/a&gt;) — and the privacy claim is verifiable by anyone: open DevTools, watch the Network tab, convert. Zero file bytes leave the device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A checklist for choosing converters.&lt;/strong&gt; If you must use a server-side tool (batch jobs, huge files), check four things before uploading anything sensitive: stated retention hours, whether the download link is authenticated, the storage jurisdiction, and whether the policy mentions filename logging. If any answer is "not stated," treat the upload as semi-public. For everyday one-file conversions, local tools remove the question entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bigger lesson.&lt;/strong&gt; "Free" was never the price question — the price was always the file. Client-side conversion doesn't just save servers money; it moves the trust boundary from a policy page to your own machine, where it belongs. Full index of our on-device tools: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Put ffmpeg in the Browser So My Servers Never See a File — Here's the Real Cost</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 19:14:10 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/i-put-ffmpeg-in-the-browser-so-my-servers-never-see-a-file-heres-the-real-cost-3mhn</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/i-put-ffmpeg-in-the-browser-so-my-servers-never-see-a-file-heres-the-real-cost-3mhn</guid>
      <description>&lt;p&gt;When we moved video processing out of our servers and into the browser tab, I expected a weekend project. It was two weeks of dead ends, and the architecture lessons were worth more than the feature. Here's the honest account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end 1: SharedArrayBuffer.&lt;/strong&gt; The 0.11-generation ffmpeg.wasm core wants &lt;code&gt;SharedArrayBuffer&lt;/code&gt;, which demands site-wide COOP/COEP headers — and those headers silently break every third-party embed on your site. One video tool nuking your analytics iframes is a bad trade. We moved to the single-threaded 0.12 core: no SAB, no headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end 2: CDN workers.&lt;/strong&gt; &lt;code&gt;new Worker('https://unpkg.com/...')&lt;/code&gt; throws SecurityError from any http origin. The blob-classURL workaround people blog about? Ignored by 0.12.10. Workers must be same-origin, period. We vendor the engine: &lt;code&gt;/assets/vendor/ffmpeg/&lt;/code&gt; served once, cached aggressively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end 3: UMD in a module worker.&lt;/strong&gt; The error &lt;code&gt;failed to import ffmpeg-core.js&lt;/code&gt; with zero detail means exactly one thing: you served the UMD core to a module worker, which does &lt;code&gt;await import(coreURL)&lt;/code&gt; and reads &lt;code&gt;.default&lt;/code&gt; — which UMD doesn't export. Serve the ESM core build. That's the whole fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bill, honestly stated.&lt;/strong&gt; 35 MB of vendored WASM (one-time, cached), conversion speed bound to the user's CPU, and honest UX limits — a browser merges two clips beautifully, not twenty. What you get in exchange is the property that matters: files never transmitted, never stored, never logged, because there is nowhere to transmit them to. Analytics stay anonymous; the Network tab shows zero file bytes leaving the device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where to see it running.&lt;/strong&gt; The same engine powers our live tools: video compression (&lt;a href="https://toolfyra.com/video-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-compressor.html&lt;/a&gt;), format conversion (&lt;a href="https://toolfyra.com/video-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-converter.html&lt;/a&gt;), trimming (&lt;a href="https://toolfyra.com/video-trimmer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-trimmer.html&lt;/a&gt;), merging (&lt;a href="https://toolfyra.com/video-merger.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-merger.html&lt;/a&gt;), audio extraction (&lt;a href="https://toolfyra.com/video-to-audio.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-to-audio.html&lt;/a&gt;), and audio conversion (&lt;a href="https://toolfyra.com/audio-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/audio-converter.html&lt;/a&gt;). Drag a file into any of them and watch the Network tab — that's the demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The transferable lesson.&lt;/strong&gt; Client-side isn't a gimmick tier; for media workloads it's the privacy architecture, and the constraints it forces — vendoring, chunking, honest limits, progress events — make the product better, not worse. If you're building anything that touches user files in 2026, ask the question before you ship: does this file actually need a server? More often than not, the answer is no.&lt;/p&gt;

&lt;p&gt;The full page index, if you want to browse everything built this way: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>webdev</category>
      <category>performance</category>
      <category>security</category>
    </item>
    <item>
      <title>The 4,200-Page Index of Free Browser Tools That Never Upload Your Files</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 19:13:30 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/the-4200-page-index-of-free-browser-tools-that-never-upload-your-files-1ni8</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/the-4200-page-index-of-free-browser-tools-that-never-upload-your-files-1ni8</guid>
      <description>&lt;p&gt;For two years I kept a private list of browser utilities that respected two rules: no signup walls, and no file ever leaves my machine. The list grew into a whole site — 4,200+ pages, every tool client-side — and people kept asking for "the index." This post is the index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rule that matters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Free online tools" usually means "upload your file to our server, get throttled, get ads." The opposite architecture exists now: WebAssembly runs real engines — ffmpeg for video, PDF libraries for documents, crypto stacks for hashing — inside your browser tab. When conversion happens on-device, privacy isn't a policy page; it's a property you can verify in the Network tab. Everything below follows that design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documents &amp;amp; PDF&lt;/strong&gt; — &lt;a href="https://toolfyra.com/pdf-merger.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-merger.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/pdf-splitter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-splitter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/word-to-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/word-to-pdf.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/pdf-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/pdf-compressor.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/epub-to-pdf.html" rel="noopener noreferrer"&gt;https://toolfyra.com/epub-to-pdf.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Images&lt;/strong&gt; — &lt;a href="https://toolfyra.com/image-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/image-compressor.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/image-resizer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/image-resizer.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/png-to-jpg.html" rel="noopener noreferrer"&gt;https://toolfyra.com/png-to-jpg.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/webp-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/webp-converter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/qr-code-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/qr-code-generator.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Video &amp;amp; audio (on-device ffmpeg)&lt;/strong&gt; — &lt;a href="https://toolfyra.com/video-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-compressor.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/video-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-converter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/video-trimmer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-trimmer.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/video-merger.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-merger.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/audio-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/audio-converter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/video-to-audio.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-to-audio.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/video-subtitle-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-subtitle-generator.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YouTube &amp;amp; social&lt;/strong&gt; — &lt;a href="https://toolfyra.com/youtube-to-mp3.html" rel="noopener noreferrer"&gt;https://toolfyra.com/youtube-to-mp3.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/youtube-to-mp4.html" rel="noopener noreferrer"&gt;https://toolfyra.com/youtube-to-mp4.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/youtube-playlist-downloader.html" rel="noopener noreferrer"&gt;https://toolfyra.com/youtube-playlist-downloader.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/youtube-video-summarizer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/youtube-video-summarizer.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/spotify-downloader.html" rel="noopener noreferrer"&gt;https://toolfyra.com/spotify-downloader.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/tiktok-to-mp3.html" rel="noopener noreferrer"&gt;https://toolfyra.com/tiktok-to-mp3.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/instagram-reels-downloader.html" rel="noopener noreferrer"&gt;https://toolfyra.com/instagram-reels-downloader.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text &amp;amp; writing&lt;/strong&gt; — &lt;a href="https://toolfyra.com/word-counter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/word-counter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/character-counter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/character-counter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/case-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/case-converter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/lorem-ipsum-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/lorem-ipsum-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/ai-essay-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/ai-essay-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/ai-story-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/ai-story-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/ai-email-writer.html" rel="noopener noreferrer"&gt;https://toolfyra.com/ai-email-writer.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculators (the deep end)&lt;/strong&gt; — &lt;a href="https://toolfyra.com/bmi-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/bmi-calculator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/age-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/age-calculator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/percentage-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/percentage-calculator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/compound-interest-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/compound-interest-calculator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/mortgage-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/mortgage-calculator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/scientific-calculator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/scientific-calculator.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security &amp;amp; developers&lt;/strong&gt; — &lt;a href="https://toolfyra.com/password-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/password-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/md5-hash-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/md5-hash-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/sha256-hash-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/sha256-hash-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/uuid-generator.html" rel="noopener noreferrer"&gt;https://toolfyra.com/uuid-generator.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/base64-encode.html" rel="noopener noreferrer"&gt;https://toolfyra.com/base64-encode.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/json-formatter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/json-formatter.html&lt;/a&gt; · &lt;a href="https://toolfyra.com/regex-tester.html" rel="noopener noreferrer"&gt;https://toolfyra.com/regex-tester.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The complete index&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Categories drift; the sitemap doesn't. The full machine-readable index of every page lives at &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt; — 4,200+ URLs, updated with each release. Bookmark it; it's the only list that never goes stale. The human-readable hub is &lt;a href="https://toolfyra.com/" rel="noopener noreferrer"&gt;https://toolfyra.com/&lt;/a&gt;, and the AI-agent-readable one is &lt;a href="https://toolfyra.com/llms.txt" rel="noopener noreferrer"&gt;https://toolfyra.com/llms.txt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two closing notes. First, everything above is free with no accounts — the business model is ads on pages, never paywalls on tools. Second, if a tool here doesn't behave the way on-device promises (watch the Network tab), that's a bug report I genuinely want.&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>privacy</category>
      <category>tools</category>
    </item>
    <item>
      <title>The one-line audit script that caught our worst bug: URLs serving the wrong tool</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 18:40:45 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/the-one-line-audit-script-that-caught-our-worst-bug-urls-serving-the-wrong-tool-emn</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/the-one-line-audit-script-that-caught-our-worst-bug-urls-serving-the-wrong-tool-emn</guid>
      <description>&lt;p&gt;TypeScript 7's speed story is great, but this week reminded me that the cheapest correctness wins usually aren't in the compiler — they're in a 40-line script you run after every deploy.&lt;/p&gt;

&lt;p&gt;Our bug: a deploy-tree drift meant some tool URLs served a &lt;em&gt;different&lt;/em&gt; tool's page. Titles said one thing, canonicals said another, content was a third. 398 pages, no type error, no test failure, no build warning — every layer was individually "green".&lt;/p&gt;

&lt;p&gt;The lesson: &lt;strong&gt;type systems verify structure, not agreement.&lt;/strong&gt; Nothing in the build knew that &lt;code&gt;video-merger.html&lt;/code&gt; should contain the string "Video Merger". So we taught it:&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="c1"&gt;# audit_site.py — runs after EVERY deploy, blocks the report if it fails
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;all_live_pages&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;canon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rel=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;canonical&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;h1&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;slug_matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;canon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 0 tolerance
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;398 pages, one HTTP sweep, under a minute. First run after the fix: &lt;code&gt;398 pages | real problems: 0&lt;/code&gt;. Before the fix it would have screamed.&lt;/p&gt;

&lt;p&gt;Three rules came out of it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The audit is a gate, not a report.&lt;/strong&gt; It runs automatically after every deploy; a red audit blocks the "done" claim — no exceptions, no "I'll check tomorrow".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebuild from one truth.&lt;/strong&gt; The drift came from two build outputs disagreeing. Now one generator, one overlay order, disk-truth sitemaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log it in the open.&lt;/strong&gt; Every task gets a START/DONE entry in a shared &lt;code&gt;AGENT-LOG.md&lt;/code&gt; on &lt;code&gt;main&lt;/code&gt; — with two agents (human-assisted) working the same repo, an append-only log beat every meeting we never had.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fast compilers make iteration cheap. A 40-line agreement checker makes &lt;em&gt;deploying&lt;/em&gt; cheap. You want both.&lt;/p&gt;

&lt;p&gt;(Tools referenced live here: &lt;a href="https://toolfyra.com" rel="noopener noreferrer"&gt;https://toolfyra.com&lt;/a&gt; — the audit covers all 398 of them.)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>testing</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Zero-retention is an architecture decision, not a policy page</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 18:40:05 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/zero-retention-is-an-architecture-decision-not-a-policy-page-bi9</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/zero-retention-is-an-architecture-decision-not-a-policy-page-bi9</guid>
      <description>&lt;p&gt;Every tool site says "we respect your privacy". Almost none can prove it, because the files you upload live on their server — even if only for seconds. "We delete it after" is a promise. Architecture is a proof.&lt;/p&gt;

&lt;p&gt;I built a 398-tool utility site (&lt;a href="https://toolfyra.com" rel="noopener noreferrer"&gt;https://toolfyra.com&lt;/a&gt;) on a simple rule: &lt;strong&gt;if a task can run client-side, the server never sees the file.&lt;/strong&gt; Not "encrypted in transit" — never touched, period.&lt;/p&gt;

&lt;p&gt;What that looks like in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Media tools&lt;/strong&gt; (compress, trim, merge, convert): ffmpeg compiled to WASM, running in the browser tab. Your 4 GB screen recording never leaves the device — it &lt;em&gt;can't&lt;/em&gt;, there's no upload path in the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documents&lt;/strong&gt; (PDF merge/split, images): same pattern with WASM libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The few API-backed tools&lt;/strong&gt; (previews, metadata): only the public URL you typed is sent — never a file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics:&lt;/strong&gt; GA4 with &lt;code&gt;anonymize_ip&lt;/code&gt;, no user IDs, no cookie walls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part isn't the tech, it's the constraints it forces on you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You can't cheat on UX.&lt;/strong&gt; Server-side tools can brute-force quality. Client-side, you budget CPU: chunking, progress events, and honest limits ("your browser can merge 2 clips, not 20").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor discipline.&lt;/strong&gt; WASM engines get vendored same-origin and version-pinned — a CDN outage can't take down your privacy story.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your privacy policy becomes short.&lt;/strong&gt; Mine basically says "we never receive your files" and it's &lt;em&gt;true by construction&lt;/em&gt;, which is the kind of claim an auditor can verify in the network tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The EU AI Act transparency wave and watermark debates are pushing this direction anyway — users are getting literate about what leaves their machine. If your privacy answer is a policy page, start moving workloads client-side now; if it's an architecture, you already have the better story to tell.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>architecture</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Shipping ffmpeg.wasm 0.12 in production without SharedArrayBuffer: every dead end, mapped</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 11 Sep 2026 18:37:41 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/shipping-ffmpegwasm-012-in-production-without-sharedarraybuffer-every-dead-end-mapped-a65</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/shipping-ffmpegwasm-012-in-production-without-sharedarraybuffer-every-dead-end-mapped-a65</guid>
      <description>&lt;p&gt;I spent a day fighting ffmpeg.wasm so you don't have to. The goal was boring: compress a video inside the browser tab, no uploads, no server bill. The journey was not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end #1 — ffmpeg.wasm 0.11.&lt;/strong&gt; It works, until you deploy. The 0.11 core needs &lt;code&gt;SharedArrayBuffer&lt;/code&gt;, which needs site-wide &lt;code&gt;COOP&lt;/code&gt;/&lt;code&gt;COEP&lt;/code&gt; headers. If your site embeds anything third-party (ads, analytics iframes, embeds), those headers silently break them. One video tool nuking your whole site's embeds is a bad trade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end #2 — cross-origin workers from a CDN.&lt;/strong&gt; "Just load the worker from unpkg" — no. &lt;code&gt;new Worker('https://unpkg.com/...')&lt;/code&gt; throws a SecurityError from any http origin. And the classURL blob workaround people suggest? 0.12.10 ignores it. I tried both, same afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead end #3 — the UMD core in a module worker.&lt;/strong&gt; This one is sneaky. The 0.12 worker is a module worker: it tries &lt;code&gt;importScripts()&lt;/code&gt; (undefined in modules → throws), then falls back to &lt;code&gt;await import(coreURL)&lt;/code&gt; and reads &lt;code&gt;.default&lt;/code&gt;. A UMD core has no default export, so you get &lt;code&gt;failed to import ffmpeg-core.js&lt;/code&gt; with zero useful detail. The fix is one URL: serve the &lt;strong&gt;ESM&lt;/strong&gt; core build, not UMD.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually shipped:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vendor the ESM build same-origin: &lt;code&gt;/assets/vendor/ffmpeg/&lt;/code&gt; (worker, classes, const, errors, utils + &lt;code&gt;esm/ffmpeg-core.js&lt;/code&gt; + wasm).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;load({ coreURL: '/assets/vendor/ffmpeg/esm/ffmpeg-core.js', wasmURL: '.../esm/ffmpeg-core.wasm' })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;COOP&lt;/code&gt;/&lt;code&gt;COEP&lt;/code&gt;. No CDN workers. No blobs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total cost: 35 MB of static assets you serve once per user (aggressively cacheable), and every conversion happens on-device. Zero uploads, zero server CPU, zero retention questions.&lt;/p&gt;

&lt;p&gt;If you want to see it working rather than read about it: I run the same engine in a browser video compressor (&lt;a href="https://toolfyra.com/video-compressor.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-compressor.html&lt;/a&gt;), a format converter (&lt;a href="https://toolfyra.com/video-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/video-converter.html&lt;/a&gt;) and an audio converter (&lt;a href="https://toolfyra.com/audio-converter.html" rel="noopener noreferrer"&gt;https://toolfyra.com/audio-converter.html&lt;/a&gt;) — drag a file in, conversion runs in your tab, and nothing ever leaves your machine.&lt;/p&gt;

&lt;p&gt;One last gotcha for the road: ESM &lt;code&gt;import()&lt;/code&gt; of your vendored files resolves relative to the &lt;em&gt;worker's&lt;/em&gt; URL. Keep the vendor directory flat and same-origin and you'll never think about it again.&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>The Real Price of "Free" Online Tools — We Audited What Happens to Your Files</title>
      <dc:creator>Tasleem Akhtar (#Ch)</dc:creator>
      <pubDate>Fri, 04 Sep 2026 12:27:22 +0000</pubDate>
      <link>https://dev.to/tasleem_akhtarch_bfb3/the-real-price-of-free-online-tools-we-audited-what-happens-to-your-files-5257</link>
      <guid>https://dev.to/tasleem_akhtarch_bfb3/the-real-price-of-free-online-tools-we-audited-what-happens-to-your-files-5257</guid>
      <description>&lt;p&gt;"Free" file tools have a business model you never see: your file. Upload-based converters quietly pay for themselves with retention — copies on disk, CDN logs, "temp" storage that isn't.&lt;/p&gt;

&lt;p&gt;We spent months auditing this space while building &lt;a href="https://toolfyra.com" rel="noopener noreferrer"&gt;Toolfyra&lt;/a&gt;, and turned the audit into a checklist you can use on any tool:&lt;/p&gt;

&lt;h3&gt;
  
  
  The 5-question audit
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Does the file leave your device at all?&lt;/strong&gt; DevTools → Network tab while converting. If a multipart upload fires, your "private" document is now their asset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What does the privacy policy say about retention?&lt;/strong&gt; "Deleted after 2 hours" still means 2 hours of their custody — and policies change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is there an account wall?&lt;/strong&gt; Email + password for a unit converter is a data-harvesting tell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where do errors go?&lt;/strong&gt; Crash reports that include filenames are a quiet leak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Could this run locally instead?&lt;/strong&gt; If the answer is yes (and for PDFs, audio, images it usually is), the upload is a choice, not a necessity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The local alternative is real now
&lt;/h3&gt;

&lt;p&gt;Modern browsers ship everything: &lt;code&gt;crypto.subtle&lt;/code&gt; for hashes, Web Audio for sound, Canvas for images, wasm for the heavy stuff. Even breach-checking can be private — the k-anonymity pattern (send only the first 5 chars of a SHA-1, like &lt;a href="https://toolfyra.com/password-strength-checker.html" rel="noopener noreferrer"&gt;our password checker&lt;/a&gt; does) proves you can query a leak database without revealing the password.&lt;/p&gt;

&lt;p&gt;All 385 of our tools process on-device; the full index and every guide is in one sitemap: &lt;a href="https://toolfyra.com/sitemap.xml" rel="noopener noreferrer"&gt;https://toolfyra.com/sitemap.xml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I run Toolfyra — but run the 5-question audit on us too. The Network tab doesn't lie.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
