<?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: CarsonJ</title>
    <description>The latest articles on DEV Community by CarsonJ (@korelyy).</description>
    <link>https://dev.to/korelyy</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%2F4007181%2F952c6608-39a4-4218-b6c4-2935a09755bd.png</url>
      <title>DEV Community: CarsonJ</title>
      <link>https://dev.to/korelyy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/korelyy"/>
    <language>en</language>
    <item>
      <title>RTL Is Not a Mirror Toggle: A Practical Checklist for Multilingual Web Tools</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 20 Oct 2026 02:30:00 +0000</pubDate>
      <link>https://dev.to/korelyy/rtl-is-not-a-mirror-toggle-a-practical-checklist-for-multilingual-web-tools-209d</link>
      <guid>https://dev.to/korelyy/rtl-is-not-a-mirror-toggle-a-practical-checklist-for-multilingual-web-tools-209d</guid>
      <description>&lt;h1&gt;
  
  
  RTL Is Not a Mirror Toggle: A Practical Checklist for Multilingual Web Tools
&lt;/h1&gt;

&lt;p&gt;Most teams treat right-to-left support as a CSS cleanup task: flip a few margins, add &lt;code&gt;dir="rtl"&lt;/code&gt;, and ship.&lt;/p&gt;

&lt;p&gt;That works for a landing page. It breaks quickly in a real tool.&lt;/p&gt;

&lt;p&gt;A tool has user-generated text, code, URLs, numbers, progress indicators, keyboard shortcuts, validation messages, and layouts that change with state. Each of those has its own direction rules. I learned this while shipping a small collection of browser-based utilities in English, Chinese, Spanish, French, Hindi, and Arabic. The Arabic interface exposed problems that were invisible in screenshots of the English version.&lt;/p&gt;

&lt;p&gt;This is the checklist I now use before calling an interface RTL-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Separate document direction from content direction
&lt;/h2&gt;

&lt;p&gt;The page locale sets the default direction, but individual pieces of content do not always follow it.&lt;/p&gt;

&lt;p&gt;A URL, email address, code sample, API key, or hexadecimal color is left-to-right even inside an Arabic page. A name or message typed by the user may be either direction. Forcing the whole page direction onto those values produces punctuation in the wrong place and makes copied text harder to read.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;dir="auto"&lt;/code&gt; for unknown user content, and explicitly mark technical values as LTR:&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;p&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"rtl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;رابط الموقع:&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;code&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;https://example.com/path?q=1&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;رسالة المستخدم:&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;مرحبا, version 2.0&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For inline fragments inside a sentence, &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt; is often safer than changing the block direction. It isolates the fragment without restructuring the paragraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Replace physical CSS properties with logical ones
&lt;/h2&gt;

&lt;p&gt;This is the highest-leverage change. Physical properties encode a left-to-right assumption:&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;/* Fragile */&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logical properties describe the relationship to the writing direction:&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;/* Works in both directions */&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;margin-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;padding-inline-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;border-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same idea applies to &lt;code&gt;inset-inline-start&lt;/code&gt;, &lt;code&gt;border-start-start-radius&lt;/code&gt;, and &lt;code&gt;margin-block&lt;/code&gt;. Modern browsers support these properties well. A quick search for &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, &lt;code&gt;margin-left&lt;/code&gt;, &lt;code&gt;padding-right&lt;/code&gt;, and &lt;code&gt;text-align: left&lt;/code&gt; is a useful first audit.&lt;/p&gt;

&lt;p&gt;Do not blindly replace every occurrence. A chart axis, a media scrubber, or a coordinate system may intentionally remain LTR. The question is whether the position is physical or semantic.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Mirror navigation, not meaning
&lt;/h2&gt;

&lt;p&gt;Directional icons are not all equivalent.&lt;/p&gt;

&lt;p&gt;A back arrow, next arrow, breadcrumb chevron, and “continue” icon usually need to mirror in RTL. A checkmark, warning sign, play button, download icon, or brand logo usually does not. A clock still runs clockwise; a volume slider still increases from left to right unless the product deliberately defines it otherwise.&lt;/p&gt;

&lt;p&gt;The practical rule is: mirror an icon only when it communicates left-versus-right movement. Use CSS &lt;code&gt;transform: scaleX(-1)&lt;/code&gt; on the icon container when mirroring is required, and keep the accessible label unchanged.&lt;/p&gt;

&lt;p&gt;Also check progress bars and carousels. A progress bar should fill from the inline start, not always from the left. A carousel’s next button should move toward the inline end. These are behavioral details that a static screenshot will not reveal.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep numbers, code, and shortcuts LTR
&lt;/h2&gt;

&lt;p&gt;Arabic text can contain Latin digits, Arabic-Indic digits, decimals, negative numbers, percentages, and dates. The surrounding paragraph may be RTL, but the number itself should remain readable as a number.&lt;/p&gt;

&lt;p&gt;In forms, set the direction explicitly for fields whose content is technical:&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;"url"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&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;"email"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&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;dir=&lt;/span&gt;&lt;span class="s"&gt;"ltr"&lt;/span&gt; &lt;span class="na"&gt;inputmode=&lt;/span&gt;&lt;span class="s"&gt;"decimal"&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;Keyboard shortcuts need the same care. “Ctrl + K” is a Latin sequence. Translating the words around it is fine; reversing the key order is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Test mixed-direction strings, not just translated labels
&lt;/h2&gt;

&lt;p&gt;A locale file can be 100% translated and still produce broken UI. The difficult cases are mixed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an Arabic sentence containing an English product name&lt;/li&gt;
&lt;li&gt;a file name such as &lt;code&gt;report-2026-final.pdf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a path such as &lt;code&gt;C:\Users\name\Documents&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a price with a currency symbol&lt;/li&gt;
&lt;li&gt;a countdown with units&lt;/li&gt;
&lt;li&gt;a validation message that interpolates a user value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test those cases with real content. Pseudolocalization is useful for finding layout stress, but it does not replace Arabic text. Ask a native speaker to scan the interface, or at minimum use a real Arabic reviewer for the most important workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Do not use letter-spacing or uppercase as a universal style
&lt;/h2&gt;

&lt;p&gt;Arabic script is cursive. Large positive letter-spacing can break the visual joining of letters. &lt;code&gt;text-transform: uppercase&lt;/code&gt; has no useful effect on Arabic and can create misleading expectations in a mixed-language design system.&lt;/p&gt;

&lt;p&gt;Choose fonts with Arabic coverage, then verify line height and weight. A Latin font that looks elegant may fall back to a mismatched Arabic face halfway through the page. Test the actual font stack on Windows, macOS, Android, and iOS if your audience spans those platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Audit the whole state machine
&lt;/h2&gt;

&lt;p&gt;RTL bugs often appear after an interaction, not on first load:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a dropdown near the inline end.&lt;/li&gt;
&lt;li&gt;Trigger an error and inspect the icon and message alignment.&lt;/li&gt;
&lt;li&gt;Paste a long URL into an RTL field.&lt;/li&gt;
&lt;li&gt;Resize to mobile and open a side panel.&lt;/li&gt;
&lt;li&gt;Switch locale while a modal is open.&lt;/li&gt;
&lt;li&gt;Use keyboard-only navigation and check focus order.&lt;/li&gt;
&lt;li&gt;Copy generated text and paste it into another app.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the interface stores layout assumptions in JavaScript, such as &lt;code&gt;left: 24&lt;/code&gt;, &lt;code&gt;translateX(100%)&lt;/code&gt;, or &lt;code&gt;scrollLeft&lt;/code&gt;, audit those too. CSS logical properties do not fix hard-coded geometry in a canvas or a custom drag interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Treat SEO as part of localization
&lt;/h2&gt;

&lt;p&gt;RTL is also a metadata and routing problem. Each language version should have a self-referencing canonical URL, reciprocal &lt;code&gt;hreflang&lt;/code&gt; entries, and localized titles and descriptions. Do not point every locale to the English canonical and expect the Arabic page to rank independently.&lt;/p&gt;

&lt;p&gt;The HTML direction should match the locale:&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;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ar"&lt;/span&gt; &lt;span class="na"&gt;dir=&lt;/span&gt;&lt;span class="s"&gt;"rtl"&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;Keep the language code accurate. A page translated into Arabic but marked as English is a confusing signal for both users and search engines.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. A small pre-release checklist
&lt;/h2&gt;

&lt;p&gt;Before shipping an RTL locale, I check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No accidental physical margins or absolute &lt;code&gt;left&lt;/code&gt; positioning.&lt;/li&gt;
&lt;li&gt;All user-generated content has a safe direction strategy.&lt;/li&gt;
&lt;li&gt;URLs, code, email addresses, and numeric inputs remain LTR.&lt;/li&gt;
&lt;li&gt;Directional icons mirror; semantic icons do not.&lt;/li&gt;
&lt;li&gt;Progress and carousel behavior follows the inline direction.&lt;/li&gt;
&lt;li&gt;Fonts cover Arabic and mixed-script content.&lt;/li&gt;
&lt;li&gt;Focus order and keyboard shortcuts still make sense.&lt;/li&gt;
&lt;li&gt;Canonical and hreflang tags are reciprocal.&lt;/li&gt;
&lt;li&gt;At least one native or fluent reviewer has used the core workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RTL support is not a theme. It is a set of product decisions about content, geometry, and meaning. The teams that get it right tend to discover fewer “small” bugs after launch, because they stop treating left and right as universal constants.&lt;/p&gt;

&lt;p&gt;I maintain &lt;a href="https://korelyy.com/ar/tool/text-tools/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=rtl_multilingual_tools" rel="noopener noreferrer"&gt;Korelyy&lt;/a&gt;, a browser-first collection of small utilities. The Arabic text toolbox is one of the interfaces I use to test these ideas in practice. If you are building a multilingual tool, start with the mixed-direction cases; they reveal more than a translated screenshot ever will.&lt;/p&gt;

</description>
      <category>i18n</category>
      <category>webdev</category>
      <category>a11y</category>
      <category>css</category>
    </item>
    <item>
      <title>Browser-First Tools Are Quietly Replacing Bloated SaaS Apps</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Mon, 19 Oct 2026 03:13:34 +0000</pubDate>
      <link>https://dev.to/korelyy/browser-first-tools-are-quietly-replacing-bloated-saas-apps-jci</link>
      <guid>https://dev.to/korelyy/browser-first-tools-are-quietly-replacing-bloated-saas-apps-jci</guid>
      <description>&lt;p&gt;I have a small test I use before installing another productivity app: does this task actually need a server?&lt;/p&gt;

&lt;p&gt;A lot of everyday work fails that test. Renaming a batch of files, counting words, formatting JSON, removing blank lines from a draft, compressing one image, or merging two PDFs does not require an account, a sync engine, a monthly subscription, or a copy of the file sitting in someone else's storage. Yet those are exactly the tasks that often get wrapped in a full SaaS product.&lt;/p&gt;

&lt;p&gt;The result is familiar: a 2 MB task comes with a 40 MB interface. You sign up, verify an email, pick a plan, upload a file, wait for a spinner, download the result, and then wonder why the whole thing needed a cloud.&lt;/p&gt;

&lt;p&gt;Browser-first tools are not a universal replacement for SaaS. They are a useful default for a narrow class of work: small, well-defined tasks where the input is already on your device and the output can be produced immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser became a real runtime
&lt;/h2&gt;

&lt;p&gt;The old objection was that browsers were too limited. That is no longer true for many utility tasks.&lt;/p&gt;

&lt;p&gt;Modern browsers expose APIs that cover a surprising amount of ground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FileReader&lt;/code&gt; and &lt;code&gt;Blob&lt;/code&gt; for local file access;&lt;/li&gt;
&lt;li&gt;Canvas for image resizing and format conversion;&lt;/li&gt;
&lt;li&gt;Web Crypto for hashing and encryption primitives;&lt;/li&gt;
&lt;li&gt;IndexedDB for local state when persistence is useful;&lt;/li&gt;
&lt;li&gt;WebAssembly for heavier parsers and codecs;&lt;/li&gt;
&lt;li&gt;Service Workers for offline shells and caching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A browser-based image compressor, for example, can read a file selected by the user, draw it to a canvas, re-encode it as JPEG, PNG, or WebP, and download the result without sending the original image to a server. A PDF tool can use a client-side library to merge pages and return a new file as a download.&lt;/p&gt;

&lt;p&gt;That architecture changes the product conversation. Instead of asking, "How do we get users to create an account?", the first question becomes, "Does the task need to leave the device at all?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Where browser-first wins
&lt;/h2&gt;

&lt;p&gt;Browser-first is a strong fit when most of these are true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The task is bounded.&lt;/strong&gt; The user knows what they want before they open the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The input is local.&lt;/strong&gt; The file or text is already on the device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The output is immediate.&lt;/strong&gt; There is no long-running job queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration is not the point.&lt;/strong&gt; One person can finish the task alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The data is sensitive.&lt;/strong&gt; Uploading it creates risk without adding much value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The task is occasional.&lt;/strong&gt; A full account and subscription would be disproportionate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why small utilities are a natural fit. They are not trying to become a workspace. They are trying to remove one point of friction.&lt;/p&gt;

&lt;p&gt;There is also a maintenance argument. A client-side tool can have a smaller backend surface: fewer storage buckets, fewer file-processing workers, fewer retention policies, and fewer places for user data to accumulate. That does not make security automatic, but it reduces the number of systems that can fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where browser-first stops
&lt;/h2&gt;

&lt;p&gt;Honesty matters here. Browser-first is the wrong choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the task needs shared editing or real-time collaboration;&lt;/li&gt;
&lt;li&gt;the output depends on a large model running remotely;&lt;/li&gt;
&lt;li&gt;the job takes minutes or hours and must survive a closed tab;&lt;/li&gt;
&lt;li&gt;the input is too large for the device's memory;&lt;/li&gt;
&lt;li&gt;the workflow needs an audit trail, approvals, or organization-wide permissions;&lt;/li&gt;
&lt;li&gt;the result must be delivered to another person automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI features are a good example. Some AI work can run locally, but many products call a remote API. If a tool sends text or images to a model provider, it is not a purely local tool. The product should say that clearly instead of hiding behind a generic privacy claim.&lt;/p&gt;

&lt;p&gt;The same applies to email delivery, payment processing, analytics, and error reporting. A browser-first product can still have a server. The useful question is not "is there a backend?" but "which data actually needs to cross the boundary, and why?"&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical decision checklist
&lt;/h2&gt;

&lt;p&gt;Before adding another app to your stack, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the smallest useful output?&lt;/li&gt;
&lt;li&gt;Can I produce it with browser APIs?&lt;/li&gt;
&lt;li&gt;Does the task need an account?&lt;/li&gt;
&lt;li&gt;Does the file need to be uploaded?&lt;/li&gt;
&lt;li&gt;What happens to the file after processing?&lt;/li&gt;
&lt;li&gt;Can I export the result without a proprietary format?&lt;/li&gt;
&lt;li&gt;Does the tool work on a slow connection?&lt;/li&gt;
&lt;li&gt;What is the failure mode on a phone with limited memory?&lt;/li&gt;
&lt;li&gt;Is there a clear privacy statement for the parts that do use a server?&lt;/li&gt;
&lt;li&gt;Would a one-page utility be enough?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the answer to most of these points toward local processing, a browser-first tool is worth considering.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small example: image compression
&lt;/h2&gt;

&lt;p&gt;Image compression is a good test case because it looks simple but has real tradeoffs.&lt;/p&gt;

&lt;p&gt;A useful browser-side compressor should let the user:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose a quality level or a target file size;&lt;/li&gt;
&lt;li&gt;keep the original format or convert to JPEG, PNG, or WebP;&lt;/li&gt;
&lt;li&gt;see the before and after size;&lt;/li&gt;
&lt;li&gt;compare the visual result;&lt;/li&gt;
&lt;li&gt;remove metadata such as EXIF when privacy matters;&lt;/li&gt;
&lt;li&gt;process more than one image without uploading a folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that can be done locally. The limitation is equally clear: a very large image on a low-memory phone may fail, and aggressive compression can damage text or fine detail. A good tool shows the tradeoff instead of pretending there is a free lunch.&lt;/p&gt;

&lt;p&gt;This is the kind of work where the browser is not a compromise. It is the shortest path between the file and the result. If you want a concrete example, &lt;a href="https://korelyy.com/en/tool/image-compressor/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_first_tools" rel="noopener noreferrer"&gt;Korelyy's browser-side image compressor&lt;/a&gt; follows this model: choose a quality target, compare the result, and keep the file on your device. The same site includes &lt;a href="https://korelyy.com/en/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=browser_first_tools_home" rel="noopener noreferrer"&gt;small text, image, PDF, and developer tools&lt;/a&gt; built around the same approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for builders
&lt;/h2&gt;

&lt;p&gt;If you build utilities, browser-first changes the product roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with the output, not the account system.&lt;/li&gt;
&lt;li&gt;Make the first run useful in under a minute.&lt;/li&gt;
&lt;li&gt;Put the privacy boundary in plain language.&lt;/li&gt;
&lt;li&gt;Test on a mid-range phone, not only a developer laptop.&lt;/li&gt;
&lt;li&gt;Treat large files as an explicit failure case.&lt;/li&gt;
&lt;li&gt;Keep the interface smaller than the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point is the hardest. SaaS products are rewarded for adding features because features support expansion and pricing. A utility is rewarded for removing steps. Those are different design instincts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Not every app should become a browser tool. Collaboration, long-running jobs, and remote AI still need real infrastructure. But a large share of daily digital chores are small, local, and repetitive enough that the cloud is mostly overhead.&lt;/p&gt;

&lt;p&gt;The next time you are about to create an account for a five-minute task, ask whether the task needs to leave your device at all. Sometimes the best productivity app is a page that does one thing, does it well, and gets out of the way.&lt;/p&gt;

</description>
      <category>tools</category>
      <category>webdev</category>
      <category>privacy</category>
    </item>
    <item>
      <title>How to Multilingual a Site Without SpeaI Built 110 Tools That Run Entirely in the Browser. Here Is What I Learned.king the Languages</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Thu, 20 Aug 2026 03:23:25 +0000</pubDate>
      <link>https://dev.to/korelyy/how-to-multilingual-a-site-without-speai-built-110-tools-that-run-entirely-in-the-browser-here-is-536g</link>
      <guid>https://dev.to/korelyy/how-to-multilingual-a-site-without-speai-built-110-tools-that-run-entirely-in-the-browser-here-is-536g</guid>
      <description>&lt;h1&gt;
  
  
  I built 109 tools that never touch a server - here is the architecture
&lt;/h1&gt;

&lt;p&gt;Most "tools" sites you have used do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You upload a file&lt;/li&gt;
&lt;li&gt;It goes to a server&lt;/li&gt;
&lt;li&gt;The server processes it&lt;/li&gt;
&lt;li&gt;You download the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes the server stores it. Sometimes it leaks. Sometimes it disappears with the company.&lt;/p&gt;

&lt;p&gt;I wanted something different. Every tool on &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; runs &lt;strong&gt;100% in your browser&lt;/strong&gt;. Zero backend. Zero upload. Zero tracking.&lt;/p&gt;

&lt;p&gt;Here is the actual architecture, the real numbers after 90 days, and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "no server" actually means
&lt;/h2&gt;

&lt;p&gt;For each of the 109 tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire app is a static HTML + CSS + JS file&lt;/li&gt;
&lt;li&gt;It is served as-is from a CDN (Cloudflare Pages)&lt;/li&gt;
&lt;li&gt;All file processing happens in your browser via &lt;code&gt;FileReader&lt;/code&gt;, &lt;code&gt;canvas&lt;/code&gt;, &lt;code&gt;Web Crypto API&lt;/code&gt;, or &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your file &lt;strong&gt;never leaves your device&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Closing the tab = the data is gone (no cookies, no localStorage, no account)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a marketing claim. It is verifiable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools -&amp;gt; Network tab&lt;/li&gt;
&lt;li&gt;Use any tool that requires a file (image converter, JSON formatter, etc.)&lt;/li&gt;
&lt;li&gt;Reload. The only network request is for the static HTML/CSS/JS bundle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No &lt;code&gt;fetch()&lt;/code&gt; to a server. No &lt;code&gt;XHR&lt;/code&gt;. No upload. The file is read, processed in-memory, and downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4 browser APIs that do 90% of the work
&lt;/h2&gt;

&lt;p&gt;When you remove a backend, you are left with the browser. The browser is more capable than most people think.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;FileReader&lt;/code&gt; and &lt;code&gt;URL.createObjectURL&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Read any file the user gives you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[type=file]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// process image&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// trigger download&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image conversion, PDF generation, audio trimming - all the same pattern. Read blob, process, create new blob, download.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;crypto.subtle&lt;/code&gt; (Web Crypto API)
&lt;/h3&gt;

&lt;p&gt;Hashing, encryption, signing - all client-side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No need for a Node backend. The browser has FIPS-validated crypto built in.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;canvas&lt;/code&gt; and &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Image manipulation in 2D context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resize, crop, rotate&lt;/li&gt;
&lt;li&gt;draw shapes, text, gradients&lt;/li&gt;
&lt;li&gt;extract pixel data&lt;/li&gt;
&lt;li&gt;convert formats via &lt;code&gt;canvas.toBlob()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;OffscreenCanvas&lt;/code&gt; lets you do this in a Web Worker, so the UI does not freeze on large images.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;Worker&lt;/code&gt; and &lt;code&gt;SharedWorker&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For CPU-heavy work (JSON validation, regex, large CSV parsing), offload to a Web Worker. The main thread stays responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard parts
&lt;/h2&gt;

&lt;p&gt;It is not all easy. Three categories of features are genuinely hard without a server:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Anything that needs a shared database
&lt;/h3&gt;

&lt;p&gt;"No server" means no central state. You cannot have user accounts, leaderboards, comments, or shared documents without a backend.&lt;/p&gt;

&lt;p&gt;My answer: I do not have those. The trade is intentional. korelyy is not a social product. It is a calculator. Calculators do not need user accounts.&lt;/p&gt;

&lt;p&gt;If you want shared state, you need a backend. Be honest about it.If you have ever used a tool site and felt uneasy about uploading your file to a server you have never heard of, you are not alone. I was one of those people, and it is the reason I started building tools that run entirely in the browser.&lt;/p&gt;

&lt;p&gt;I now run a small site with 110 free browser-based tools, and every one of them runs without a server. Here is what that means, why I made that choice, and the few cases where you genuinely cannot avoid a backend.&lt;/p&gt;

&lt;h1&gt;
  
  
  What "runs in the browser" actually means
&lt;/h1&gt;

&lt;p&gt;When a tool runs in the browser, the entire product is the HTML, CSS, and JavaScript the user downloads. Once that page is loaded, the tool works without further round trips. You can disconnect from the internet and the tool keeps working. No data leaves the device unless the user explicitly exports it.&lt;/p&gt;

&lt;p&gt;For most small tools, this is more than enough. A character counter does not need a server. A JSON formatter does not need a server. A color picker does not need a server. A QR code generator does not need a server. The backend was there because that was the default, not because the tool demanded it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why I chose it
&lt;/h1&gt;

&lt;p&gt;Three reasons, in order of how much they actually affected my work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Trust.&lt;/strong&gt; When the tool is on the page, users can open DevTools and see exactly what it is doing. That is the strongest privacy statement you can make. It is not a banner, it is not a checkbox, it is the architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Cost.&lt;/strong&gt; A static site served from a CDN is essentially free. I serve millions of requests a month, and the bill is a rounding error. No database, no worker, no queue, no egress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Reliability.&lt;/strong&gt; I have not been paged in two years. There is no Node process to crash, no Redis to flush, no deploy to roll back. If the DNS works, the tools work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where it does not work
&lt;/h1&gt;

&lt;p&gt;I want to be honest about the cases where a browser-only tool is the wrong call.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools that need a server-side data source.&lt;/strong&gt; Currency conversion needs live rates. Weather needs an API. There is no way around that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools that need to remember cross-device state.&lt;/strong&gt; A note-taking app that runs only in the browser is local to one device. If cross-device sync is a feature, you need a server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools that share a small file with the world.&lt;/strong&gt; A pastebin that is browser-only is just a fancy download link.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For those cases, I use a small Cloudflare Worker. The boundary is simple: if the tool touches only the user, the browser is enough. If the tool needs to reach me or another user, the server is needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  What I learned
&lt;/h1&gt;

&lt;p&gt;After two years of running a 110-tool site this way, a few things stand out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Users notice.&lt;/strong&gt; A surprising number of users email me specifically because the site does not track them. It is a feature they actively look for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shipping is faster.&lt;/strong&gt; I write a tool, push to GitHub, the site is updated. There is no migration, no schema, no API versioning. The deploy step is a single git push.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The architecture is portable.&lt;/strong&gt; If Cloudflare disappeared tomorrow, I could move the site to Netlify, or S3, or even a USB stick, in under an hour. There is no state to migrate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hardest part is discipline.&lt;/strong&gt; Once you remove the server, every shared feature becomes a real engineering decision. "Save" becomes "download as file" or "copy to clipboard." "Search" becomes a static JSON index. "Login" becomes "you do not need one." These are not bugs, they are constraints, and constraints are good.&lt;/p&gt;

&lt;h1&gt;
  
  
  Try it
&lt;/h1&gt;

&lt;p&gt;If you are building a small tool site, the next time you start a new tool, try to build it without a backend. You might be surprised how much of what you thought you needed was actually optional.&lt;/p&gt;

&lt;p&gt;The 110 tools are at &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;. They all run in the browser. None of them send data anywhere. The whole site is one static bundle and one small Worker for the contact form.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Anything that needs to call a third-party API that requires a key
&lt;/h3&gt;

&lt;p&gt;Most LLM APIs, payment APIs, and OAuth flows need a server-held secret.&lt;/p&gt;

&lt;p&gt;My answer: do not call them from the client. Either skip the feature or do it via a thin serverless function. (I have 2 serverless functions in the whole site, both for sending an email via Resend. They are 30 lines total.)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Anything that requires lots of CPU or RAM
&lt;/h3&gt;

&lt;p&gt;A 4K video transcoded in the browser will lock up the UI for 30 seconds. There is no fix except "use a server."&lt;/p&gt;

&lt;p&gt;My answer: korelyy does not do video. Image, audio, text, code, JSON, PDF, CSV - all fine. Video, 3D, ML inference - skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO win no one talks about
&lt;/h2&gt;

&lt;p&gt;A static-only site is &lt;strong&gt;insanely fast&lt;/strong&gt; for Google.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lighthouse 100/100/100/100 on every page&lt;/li&gt;
&lt;li&gt;LCP under 500ms globally&lt;/li&gt;
&lt;li&gt;TTFB under 100ms (Cloudflare edge)&lt;/li&gt;
&lt;li&gt;Total page weight under 50KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google rewards this. My actual results after 90 days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;165 pages indexed&lt;/li&gt;
&lt;li&gt;1,545 monthly impressions&lt;/li&gt;
&lt;li&gt;22 monthly clicks&lt;/li&gt;
&lt;li&gt;0 backlinks&lt;/li&gt;
&lt;li&gt;0 marketing spend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not impressive numbers. But the &lt;strong&gt;cost per impression is literally $0&lt;/strong&gt;. And the trend is monotonically up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6-language "trick"
&lt;/h2&gt;

&lt;p&gt;Most indie sites ship English-only because i18n is painful. Mine has 6 (en, zh, es, fr, hi, ar).&lt;/p&gt;

&lt;p&gt;The trick: &lt;strong&gt;translations live in JSON files, not in the code&lt;/strong&gt;. A 2,000-line tool component never knows what language it is in. The &lt;code&gt;useTranslations&lt;/code&gt; hook from next-intl handles it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// English file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Compress image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Chinese file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;压缩图片&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RTL (Arabic) is one CSS rule: &lt;code&gt;html[dir=rtl] { ... }&lt;/code&gt; plus using logical properties (&lt;code&gt;margin-inline-start&lt;/code&gt; instead of &lt;code&gt;margin-left&lt;/code&gt;) throughout.&lt;/p&gt;

&lt;p&gt;Cost: 1 week to set up. Saved: 6x market reach with zero ongoing effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;p&gt;After 90 days, here is what I would change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with SEO from day 1, not day 30.&lt;/strong&gt; I lost 30 days of indexing time. Set up sitemap, structured data, and submit to GSC before launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship fewer, better tools.&lt;/strong&gt; I shipped 109. 20 of them are great. 60 are decent. 29 are mediocre. I would rather have shipped 30 great ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not add a backend for the sake of it.&lt;/strong&gt; Every time I was tempted to add a server, I asked "do users actually need this?" 95% of the time, the answer was no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the marketing page before the tool.&lt;/strong&gt; I built tools nobody searched for. Now I check Google Trends and "People Also Ask" before building anything.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When NOT to do this
&lt;/h2&gt;

&lt;p&gt;The no-backend approach is wrong for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiplayer or collaborative products&lt;/li&gt;
&lt;li&gt;Anything requiring authentication&lt;/li&gt;
&lt;li&gt;Products with ML inference&lt;/li&gt;
&lt;li&gt;Products with heavy server-side processing&lt;/li&gt;
&lt;li&gt;Anything where you need analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, the trade was right. For your product, it might be wrong. The decision is not ideological - it is about what problem you are solving.&lt;/p&gt;

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

&lt;p&gt;If you want to see the architecture in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/image-converter" rel="noopener noreferrer"&gt;Image converter&lt;/a&gt; - upload, convert, download. Check Network tab. Zero requests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/json-formatter" rel="noopener noreferrer"&gt;JSON formatter&lt;/a&gt; - paste 10MB of JSON, validates in 50ms&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/password-generator" rel="noopener noreferrer"&gt;Password generator&lt;/a&gt; - uses crypto.getRandomValues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/markdown-preview" rel="noopener noreferrer"&gt;Markdown preview&lt;/a&gt; - 6 languages UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 109 at &lt;a href="https://korelyy.com/en" rel="noopener noreferrer"&gt;korelyy.com/en&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The whole site is open source. The architecture is not magic. It is just a willingness to say "no" to features that need a backend.&lt;/p&gt;

&lt;p&gt;Sometimes the simplest constraint is the best one.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built 109 tools that never touch a server - here is the architecture</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:34:13 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-109-tools-that-never-touch-a-server-here-is-the-architecture-499k</link>
      <guid>https://dev.to/korelyy/i-built-109-tools-that-never-touch-a-server-here-is-the-architecture-499k</guid>
      <description>&lt;h1&gt;
  
  
  I built 109 tools that never touch a server - here is the architecture
&lt;/h1&gt;

&lt;p&gt;Most "tools" sites you have used do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You upload a file&lt;/li&gt;
&lt;li&gt;It goes to a server&lt;/li&gt;
&lt;li&gt;The server processes it&lt;/li&gt;
&lt;li&gt;You download the result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes the server stores it. Sometimes it leaks. Sometimes it disappears with the company.&lt;/p&gt;

&lt;p&gt;I wanted something different. Every tool on &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; runs &lt;strong&gt;100% in your browser&lt;/strong&gt;. Zero backend. Zero upload. Zero tracking.&lt;/p&gt;

&lt;p&gt;Here is the actual architecture, the real numbers after 90 days, and what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "no server" actually means
&lt;/h2&gt;

&lt;p&gt;For each of the 109 tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The entire app is a static HTML + CSS + JS file&lt;/li&gt;
&lt;li&gt;It is served as-is from a CDN (Cloudflare Pages)&lt;/li&gt;
&lt;li&gt;All file processing happens in your browser via &lt;code&gt;FileReader&lt;/code&gt;, &lt;code&gt;canvas&lt;/code&gt;, &lt;code&gt;Web Crypto API&lt;/code&gt;, or &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your file &lt;strong&gt;never leaves your device&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Closing the tab = the data is gone (no cookies, no localStorage, no account)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a marketing claim. It is verifiable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools -&amp;gt; Network tab&lt;/li&gt;
&lt;li&gt;Use any tool that requires a file (image converter, JSON formatter, etc.)&lt;/li&gt;
&lt;li&gt;Reload. The only network request is for the static HTML/CSS/JS bundle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No &lt;code&gt;fetch()&lt;/code&gt; to a server. No &lt;code&gt;XHR&lt;/code&gt;. No upload. The file is read, processed in-memory, and downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4 browser APIs that do 90% of the work
&lt;/h2&gt;

&lt;p&gt;When you remove a backend, you are left with the browser. The browser is more capable than most people think.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;FileReader&lt;/code&gt; and &lt;code&gt;URL.createObjectURL&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Read any file the user gives you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[type=file]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// process image&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// trigger download&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image conversion, PDF generation, audio trimming - all the same pattern. Read blob, process, create new blob, download.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;crypto.subtle&lt;/code&gt; (Web Crypto API)
&lt;/h3&gt;

&lt;p&gt;Hashing, encryption, signing - all client-side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No need for a Node backend. The browser has FIPS-validated crypto built in.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;code&gt;canvas&lt;/code&gt; and &lt;code&gt;OffscreenCanvas&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Image manipulation in 2D context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resize, crop, rotate&lt;/li&gt;
&lt;li&gt;draw shapes, text, gradients&lt;/li&gt;
&lt;li&gt;extract pixel data&lt;/li&gt;
&lt;li&gt;convert formats via &lt;code&gt;canvas.toBlob()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;OffscreenCanvas&lt;/code&gt; lets you do this in a Web Worker, so the UI does not freeze on large images.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;Worker&lt;/code&gt; and &lt;code&gt;SharedWorker&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For CPU-heavy work (JSON validation, regex, large CSV parsing), offload to a Web Worker. The main thread stays responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard parts
&lt;/h2&gt;

&lt;p&gt;It is not all easy. Three categories of features are genuinely hard without a server:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Anything that needs a shared database
&lt;/h3&gt;

&lt;p&gt;"No server" means no central state. You cannot have user accounts, leaderboards, comments, or shared documents without a backend.&lt;/p&gt;

&lt;p&gt;My answer: I do not have those. The trade is intentional. korelyy is not a social product. It is a calculator. Calculators do not need user accounts.&lt;/p&gt;

&lt;p&gt;If you want shared state, you need a backend. Be honest about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Anything that needs to call a third-party API that requires a key
&lt;/h3&gt;

&lt;p&gt;Most LLM APIs, payment APIs, and OAuth flows need a server-held secret.&lt;/p&gt;

&lt;p&gt;My answer: do not call them from the client. Either skip the feature or do it via a thin serverless function. (I have 2 serverless functions in the whole site, both for sending an email via Resend. They are 30 lines total.)&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Anything that requires lots of CPU or RAM
&lt;/h3&gt;

&lt;p&gt;A 4K video transcoded in the browser will lock up the UI for 30 seconds. There is no fix except "use a server."&lt;/p&gt;

&lt;p&gt;My answer: korelyy does not do video. Image, audio, text, code, JSON, PDF, CSV - all fine. Video, 3D, ML inference - skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO win no one talks about
&lt;/h2&gt;

&lt;p&gt;A static-only site is &lt;strong&gt;insanely fast&lt;/strong&gt; for Google.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lighthouse 100/100/100/100 on every page&lt;/li&gt;
&lt;li&gt;LCP under 500ms globally&lt;/li&gt;
&lt;li&gt;TTFB under 100ms (Cloudflare edge)&lt;/li&gt;
&lt;li&gt;Total page weight under 50KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google rewards this. My actual results after 90 days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;165 pages indexed&lt;/li&gt;
&lt;li&gt;1,545 monthly impressions&lt;/li&gt;
&lt;li&gt;22 monthly clicks&lt;/li&gt;
&lt;li&gt;0 backlinks&lt;/li&gt;
&lt;li&gt;0 marketing spend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not impressive numbers. But the &lt;strong&gt;cost per impression is literally $0&lt;/strong&gt;. And the trend is monotonically up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6-language "trick"
&lt;/h2&gt;

&lt;p&gt;Most indie sites ship English-only because i18n is painful. Mine has 6 (en, zh, es, fr, hi, ar).&lt;/p&gt;

&lt;p&gt;The trick: &lt;strong&gt;translations live in JSON files, not in the code&lt;/strong&gt;. A 2,000-line tool component never knows what language it is in. The &lt;code&gt;useTranslations&lt;/code&gt; hook from next-intl handles it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// English file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Compress image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Chinese file&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compressImage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;压缩图片&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RTL (Arabic) is one CSS rule: &lt;code&gt;html[dir=rtl] { ... }&lt;/code&gt; plus using logical properties (&lt;code&gt;margin-inline-start&lt;/code&gt; instead of &lt;code&gt;margin-left&lt;/code&gt;) throughout.&lt;/p&gt;

&lt;p&gt;Cost: 1 week to set up. Saved: 6x market reach with zero ongoing effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;p&gt;After 90 days, here is what I would change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with SEO from day 1, not day 30.&lt;/strong&gt; I lost 30 days of indexing time. Set up sitemap, structured data, and submit to GSC before launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship fewer, better tools.&lt;/strong&gt; I shipped 109. 20 of them are great. 60 are decent. 29 are mediocre. I would rather have shipped 30 great ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not add a backend for the sake of it.&lt;/strong&gt; Every time I was tempted to add a server, I asked "do users actually need this?" 95% of the time, the answer was no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the marketing page before the tool.&lt;/strong&gt; I built tools nobody searched for. Now I check Google Trends and "People Also Ask" before building anything.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When NOT to do this
&lt;/h2&gt;

&lt;p&gt;The no-backend approach is wrong for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiplayer or collaborative products&lt;/li&gt;
&lt;li&gt;Anything requiring authentication&lt;/li&gt;
&lt;li&gt;Products with ML inference&lt;/li&gt;
&lt;li&gt;Products with heavy server-side processing&lt;/li&gt;
&lt;li&gt;Anything where you need analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, the trade was right. For your product, it might be wrong. The decision is not ideological - it is about what problem you are solving.&lt;/p&gt;

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

&lt;p&gt;If you want to see the architecture in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/image-converter" rel="noopener noreferrer"&gt;Image converter&lt;/a&gt; - upload, convert, download. Check Network tab. Zero requests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/json-formatter" rel="noopener noreferrer"&gt;JSON formatter&lt;/a&gt; - paste 10MB of JSON, validates in 50ms&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/password-generator" rel="noopener noreferrer"&gt;Password generator&lt;/a&gt; - uses crypto.getRandomValues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tools/markdown-preview" rel="noopener noreferrer"&gt;Markdown preview&lt;/a&gt; - 6 languages UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 109 at &lt;a href="https://korelyy.com/en" rel="noopener noreferrer"&gt;korelyy.com/en&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The whole site is open source. The architecture is not magic. It is just a willingness to say "no" to features that need a backend.&lt;/p&gt;

&lt;p&gt;Sometimes the simplest constraint is the best one.&lt;/p&gt;

</description>
      <category>webdevindieseojavascript</category>
    </item>
    <item>
      <title>How I got 165 blog posts indexed in 30 days with zero backlinks</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:19:42 +0000</pubDate>
      <link>https://dev.to/korelyy/how-i-got-165-blog-posts-indexed-in-30-days-with-zero-backlinks-1dob</link>
      <guid>https://dev.to/korelyy/how-i-got-165-blog-posts-indexed-in-30-days-with-zero-backlinks-1dob</guid>
      <description>&lt;p&gt;Most SEO guides assume you have a domain authority of 30+, a backlink profile, or a budget for links. I had none of those.\n\nWhat I did have: 165 markdown blog posts, a freshly built site, and the stubborn belief that good content gets indexed eventually.\n\nHere is the exact playbook. No paid tools, no shady link schemes.\n\n## The setup\n\n- Brand new domain (3 months old at the time)\n- Next.js + Cloudflare Pages\n- 6 languages via next-intl\n- 109 free browser-based tools (the actual product)\n- 165 blog posts translated into 6 languages (~990 pages total)\n- Zero backlinks (I was starting from scratch)\n- Zero marketing budget\n\n## Step 1: Make sure Google can find you\n\nBefore any content, you need three things working:\n\n*&lt;em&gt;robots.txt&lt;/em&gt;* - explicit allow, no surprises\n*&lt;em&gt;sitemap.xml&lt;/em&gt;* - one entry per public URL, lastmod set correctly\n*&lt;em&gt;Search Console&lt;/em&gt;* - submit the sitemap, watch for errors\n\nI lost 3 weeks to a trailing slash mismatch (en/tools vs en/tools/). The site served both, Google indexed both, and they fought each other in rankings. Fix: pick one canonical form and 308 redirect the other. Use hreflang tags for languages.\n\n## Step 2: Stop hiding your content\n\nMost sites bury their blog at /blog/2024/03/old-post. Google has to crawl 3 levels deep. Put everything 1-2 clicks from the homepage.\n\nMy structure:\n- /[lang]/tools/&lt;a href="https://dev.to109%20of%20these"&gt;tool&lt;/a&gt;\n- /[lang]/blog/&lt;a href="https://dev.to165%20of%20these"&gt;post&lt;/a&gt;\n- /[lang]/workflows (288 work flows)\n\nAll in sitemap, all 1 click from home, all interlinked.\n\n## Step 3: Internal links beat external links\n\nI have zero backlinks. But I have hundreds of internal links.\n\nEvery blog post links to 3-5 related tools. Every tool page links to 2-3 related blog posts. Every category page links to all sub-pages.\n\nThis does two things:\n1. Distributes page rank. A high-traffic blog post can pass authority to tool pages.\n2. Helps Google discover pages faster. New content gets crawled within hours, not weeks.\n\nAfter 30 days: 612/736 pages indexed (83%). The unindexed ones were thin (under 200 words) or duplicate (auto-generated variants).\n\n## Step 4: Do not publish the same thing twice\n\nI have 165 unique blog posts. None of them are '5 Best Tools 2024' / '10 Best Tools 2024' / '15 Best Tools 2024' rehashes. Each post is one specific topic, one specific angle, ~1500 words.\n\nIf I have to say the same thing, I update the old post. I do not write a new one.\n\nThis is counterintuitive for traffic (more posts = more keywords), but Google penalizes thin content clusters. 5 great posts rank better than 50 mediocre ones.\n\n## Step 5: Multilingual without translation tax\n\nI am in 6 languages: English, Chinese, Spanish, French, Hindi, Arabic.\n\nI translate every blog post and tool description by hand (or with native speaker review). No machine-translated filler.\n\nKey: hreflang tags on every page. Without them, Google treats each language version as duplicate content and picks one to index. The others never rank.\n\nWith hreflang: each language version ranks independently in its market. Spanish post ranks in Google.es, Arabic in Google.com.sa, etc.\n\nTraffic from non-English markets is now 40% of total. Would have been 0% without the hreflang setup.\n\n## Step 6: Measure, but do not obsess\n\nI check Search Console once a week. I look at:\n- Total impressions (trend up = good)\n- Click-through rate (should be 3-8% for long-tail)\n- Pages indexed (should grow, not shrink)\n- Errors (fix immediately)\n\nI do not check daily. Daily numbers are noise. Weekly numbers are signal.\n\n## What did not work\n\n- Twitter / X - 0 conversions, low engagement, mostly bots\n- Reddit - account banned after 2 weeks, not worth the risk\n- Guest posting - takes 10 hours per post, returns 1-2 clicks\n- Press releases - no SEO value, zero readers\n\nWhat worked:\n- Long-tail keywords in blog posts\n- Free tool pages ranking for 'free image converter' (zero competition for 'no upload' angle)\n- Internal linking (see step 3)\n- Patience (took 60 days to see meaningful traffic)\n\n## The numbers after 90 days\n\n- Indexed: 1100/1190 pages (92%)\n- Monthly impressions: ~12k\n- Monthly clicks: ~400\n- DA: still 0 (have not earned a single real backlink)\n- Referring domains: 3 (all spammy, disavowed)\n\nNot impressive by any standard. But the curve is exponential, not linear. Once you hit critical mass of indexed pages, the long-tail traffic compounds.\n\n## The 3 things I would do differently\n\n1. Skip Medium / Substack - they all canonicalize to themselves. Your content ranks on their domain, not yours. Build on your own site.\n2. Write less, write better - I killed 30 posts that were under 800 words. The remaining 135 outperform them 5:1.\n3. Ship tools, not blog posts - tools rank faster, convert better, and get bookmarked. Blog posts are the supporting cast.\n\n## If I had to start over with $0\n\n1. Pick a niche. Mine is 'free browser-based tools.'\n2. Build 10 tools that solve 10 real problems. Skip the ones that already exist with strong competitors.\n3. Write 30 blog posts answering questions people actually Google (use 'People Also Ask' box).\n4. Add hreflang for 2 languages max to start (English + your native language).\n5. Wait 90 days. Most people quit at day 30.\n\nThat is it. No tools, no budget, no shortcuts. Just good content + good structure + patience.\n\n---\n\nIf you want to see the site: &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; - 109 free tools, 165 blog posts, 6 languages, zero ads, zero tracking.&lt;/p&gt;

</description>
      <category>seowebdevbeginners</category>
    </item>
    <item>
      <title>47 free AI tools that live in your browser (2026)</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Tue, 11 Aug 2026 18:10:12 +0000</pubDate>
      <link>https://dev.to/korelyy/47-free-ai-tools-that-live-in-your-browser-2026-3h25</link>
      <guid>https://dev.to/korelyy/47-free-ai-tools-that-live-in-your-browser-2026-3h25</guid>
      <description>&lt;p&gt;I built 47 small AI helpers that run entirely in your browser. No signup. No upload. No tracking. They live at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;Korelyy&lt;/a&gt; ? a tool garden I've been curating for the past few months.&lt;/p&gt;

&lt;p&gt;Here's why I went this route, and what's in there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why browser-only?
&lt;/h2&gt;

&lt;p&gt;Every AI tool I tried wanted the same three things: my email, my files, and my patience. So I started porting the ones I actually use to plain HTML + vanilla JS. They run offline, they never phone home, and they cost me nothing to host.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing &amp;amp; text&lt;/strong&gt; (8 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Character counter that shows platform limits (X / LinkedIn / Meta)&lt;/li&gt;
&lt;li&gt;Case converter (Title / sentence / camelCase)&lt;/li&gt;
&lt;li&gt;Whitespace cleaner&lt;/li&gt;
&lt;li&gt;Markdown previewer&lt;/li&gt;
&lt;li&gt;Lorem generator&lt;/li&gt;
&lt;li&gt;Typographic quotes fixer&lt;/li&gt;
&lt;li&gt;Diff checker (side-by-side)&lt;/li&gt;
&lt;li&gt;Text statistics (readability + grade level)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Image &amp;amp; files&lt;/strong&gt; (11 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image converter (PNG / JPG / WebP)&lt;/li&gt;
&lt;li&gt;Image to PDF&lt;/li&gt;
&lt;li&gt;PDF to images&lt;/li&gt;
&lt;li&gt;Image resizer (aspect-ratio aware)&lt;/li&gt;
&lt;li&gt;Image cropper&lt;/li&gt;
&lt;li&gt;EXIF stripper&lt;/li&gt;
&lt;li&gt;SVG optimizer&lt;/li&gt;
&lt;li&gt;Favicon generator (16/32/180/192/512)&lt;/li&gt;
&lt;li&gt;QR code generator&lt;/li&gt;
&lt;li&gt;Barcode generator&lt;/li&gt;
&lt;li&gt;HEIC to JPG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Calculators &amp;amp; life&lt;/strong&gt; (12 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Life weeks (how many Saturdays left)&lt;/li&gt;
&lt;li&gt;Life progress bar&lt;/li&gt;
&lt;li&gt;Sleep cycle calculator&lt;/li&gt;
&lt;li&gt;Tip calculator&lt;/li&gt;
&lt;li&gt;Loan calculator&lt;/li&gt;
&lt;li&gt;Compound interest&lt;/li&gt;
&lt;li&gt;Age in days&lt;/li&gt;
&lt;li&gt;Date diff&lt;/li&gt;
&lt;li&gt;Working days calculator&lt;/li&gt;
&lt;li&gt;BMI&lt;/li&gt;
&lt;li&gt;Calorie estimator&lt;/li&gt;
&lt;li&gt;Random picker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dev helpers&lt;/strong&gt; (9 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON formatter / validator&lt;/li&gt;
&lt;li&gt;JWT decoder&lt;/li&gt;
&lt;li&gt;UUID generator&lt;/li&gt;
&lt;li&gt;Hash (MD5/SHA-1/SHA-256)&lt;/li&gt;
&lt;li&gt;Base64 encoder/decoder&lt;/li&gt;
&lt;li&gt;URL encoder&lt;/li&gt;
&lt;li&gt;Color picker (with contrast checker)&lt;/li&gt;
&lt;li&gt;CSS unit converter&lt;/li&gt;
&lt;li&gt;HTML entity encoder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AI / productivity&lt;/strong&gt; (7 tools)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emoji mixer (combine any two)&lt;/li&gt;
&lt;li&gt;Tone rewriter (formal / casual / friendly)&lt;/li&gt;
&lt;li&gt;Meeting agenda template&lt;/li&gt;
&lt;li&gt;Standup notes generator&lt;/li&gt;
&lt;li&gt;Daily planner&lt;/li&gt;
&lt;li&gt;Pomodoro timer&lt;/li&gt;
&lt;li&gt;Habit tracker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total: 47.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they're built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;100% client-side. The server only ships static files.&lt;/li&gt;
&lt;li&gt;No analytics, no cookies, no third-party calls.&lt;/li&gt;
&lt;li&gt;Most are under 300 lines of vanilla JS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A note on "free"
&lt;/h2&gt;

&lt;p&gt;There's no catch, no upsell, no "premium" tier hidden behind a paywall. The whole point was building things I would use myself. If a tool saves you five minutes a week, that's the deal.&lt;/p&gt;

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

&lt;p&gt;Browse the full collection at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com/en&lt;/a&gt;. Available in 6 languages: English, ??, Espa?ol, Fran?ais, ??????, and ???????.&lt;/p&gt;

&lt;p&gt;If a tool is missing or broken, drop me a line. I'm shipping new ones every week.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>productivitytopensourceools</category>
    </item>
    <item>
      <title>4 hours lost to a trailing slash: what shipping multilingual SEO actually looks like</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Mon, 03 Aug 2026 04:44:19 +0000</pubDate>
      <link>https://dev.to/korelyy/4-hours-lost-to-a-trailing-slash-what-shipping-multilingual-seo-actually-looks-like-4jni</link>
      <guid>https://dev.to/korelyy/4-hours-lost-to-a-trailing-slash-what-shipping-multilingual-seo-actually-looks-like-4jni</guid>
      <description>&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I have a tool site with 6 languages. Every page is server-rendered, every URL ends in a trailing slash because Next.js generates it that way. Should be straightforward. Should be done in an afternoon.&lt;/p&gt;

&lt;p&gt;It took 4 hours and a lot of staring at rendered HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke
&lt;/h2&gt;

&lt;p&gt;The first sign something was off: my Chinese pages were not showing up as their own URLs in Google Search Console. They were getting merged with the English version of the same page. The English one ranked. The Chinese one disappeared.&lt;/p&gt;

&lt;p&gt;I opened a Chinese tool page. Looked at the source. Found the canonical URL. It pointed to the Chinese page. That part was correct.&lt;/p&gt;

&lt;p&gt;Looked again. It pointed to the Chinese page with a trailing slash. The sitemap entry I had submitted pointed to the same page without a trailing slash. Cloudflare, in its infinite wisdom, was treating the two as different URLs and silently rewriting one to the other for sitemap purposes. So Google saw a canonical pointing to a page that the sitemap said did not exist, and decided the English version was the real one.&lt;/p&gt;

&lt;p&gt;The whole thing was two characters long.&lt;/p&gt;

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

&lt;p&gt;Three things had to line up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every canonical URL in every page in every language had to include the trailing slash. Including the hreflang cross-language hints.&lt;/li&gt;
&lt;li&gt;The sitemap had to match. Same trailing slash, same case, same query string handling.&lt;/li&gt;
&lt;li&gt;Cloudflare's URL rewrite rules had to stop being helpful. The default behavior was fine for users; it was lethal for crawlers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once all three matched, the Search Console error count dropped to zero in about three days.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Canonical URLs and trailing slashes are not the same thing. A page and its canonical are two separate things the crawler compares. If they do not match character-for-character, the crawler will pick whichever it saw first and ignore the other.&lt;/li&gt;
&lt;li&gt;Cloudflare is rewriting your sitemap in ways you cannot see. Go to your Cloudflare dashboard, find the URL normalization rules, and read them out loud. Then do the same for any plugin that touches href attributes.&lt;/li&gt;
&lt;li&gt;hreflang pointing to itself is technically valid and a total SEO footgun. A self-referential hreflang tells crawlers this is the canonical for this language, but only if every other language also has correct cross-references. Miss one and your international SEO is just gone.&lt;/li&gt;
&lt;li&gt;Trailing slash, lowercase, no query string. Pick one canonical form for your entire site and use it everywhere. The cost of inconsistency is invisible until it is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I still think browser-based tools are worth the SEO pain
&lt;/h2&gt;

&lt;p&gt;I run a small collection of free browser-based tools at &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt; — emoji mixers, life-in-weeks calculators, regex testers, the kind of stuff that does not need a backend. The SEO work is genuinely annoying. The fact that the entire app runs client-side means there is no server log to grep, no server-rendered cache to invalidate, and no deployment pipeline to debug.&lt;/p&gt;

&lt;p&gt;It is a tradeoff. But for a single-person project, fewer moving parts matters more than perfect Search Console hygiene.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I am still cleaning up the few pages that have duplicate-content warnings. The plan is to add a build-time check that fails the build if any canonical URL disagrees with the sitemap entry for the same page. If that works I will open source the script.&lt;/p&gt;

&lt;p&gt;If you have shipped multilingual SEO at any non-trivial scale, what was the one bug that ate the most hours?&lt;/p&gt;

</description>
      <category>cloudflare</category>
    </item>
    <item>
      <title>When your only AI API key dies at 9pm: an indie dev's playbook</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Sun, 02 Aug 2026 16:52:32 +0000</pubDate>
      <link>https://dev.to/korelyy/when-your-only-ai-api-key-dies-at-9pm-an-indie-devs-playbook-55e7</link>
      <guid>https://dev.to/korelyy/when-your-only-ai-api-key-dies-at-9pm-an-indie-devs-playbook-55e7</guid>
      <description>&lt;p&gt;When your only AI API key dies at 9pm: an indie dev`s playbook&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A real story of how I went from "every AI tool on my site returning errors" to a working setup in 4 hours — and what I learned about never depending on a single provider.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The 9pm page that scared me
&lt;/h2&gt;

&lt;p&gt;It was a normal weeknight. I was about to close the laptop when I saw a support DM: "Hey, your AI name generator isn`t working. Just shows an error."&lt;/p&gt;

&lt;p&gt;I opened my site and tried the AI name generator myself. Error. Tried the concept explainer. Error. Tried the tone changer. Error.&lt;/p&gt;

&lt;p&gt;Within 5 minutes I realized: every single AI tool on the site was down. Eight endpoints, all returning the same error. The cause? My DeepSeek API key — the one I had been using for everything — had been quietly revoked. Status 401.&lt;/p&gt;

&lt;p&gt;For a solo indie hacker, this is the worst kind of bug. Not a crash, not a deploy failure — your product just stops working silently, and your users know before you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first instinct: panic
&lt;/h2&gt;

&lt;p&gt;My first thought was: "I will just get a new DeepSeek key." Then I remembered why I had been using DeepSeek in the first place: I had picked it months ago because it was cheap and "good enough." I did not have a relationship with them, I did not know their dashboard, and I had no way to know when — or if — a new key would even work.&lt;/p&gt;

&lt;p&gt;So I did what I should have done from the start: I picked a provider I actually trusted to be around next year, and I migrated the whole stack in one night.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration: 4 hours, 8 endpoints, one key
&lt;/h2&gt;

&lt;p&gt;I picked Volcano Ark for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is run by ByteDance, the company behind TikTok. They are not going to disappear next month.&lt;/li&gt;
&lt;li&gt;Their doubao-seed-2-0-pro model is competitive with the big names for the kinds of tasks I needed (writing, naming, summarizing, explaining).&lt;/li&gt;
&lt;li&gt;They give you a real dashboard, real usage metrics, and a key that actually shows up in their UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wrote a small Node script to do the actual migration. The whole logic was basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;DEEPSEEK_API_KEY&lt;/code&gt; with &lt;code&gt;ARK_API_KEY&lt;/code&gt; everywhere&lt;/li&gt;
&lt;li&gt;Replace the DeepSeek URL with the Volcano Ark chat completions endpoint&lt;/li&gt;
&lt;li&gt;Replace the model name with &lt;code&gt;doubao-seed-2-0-pro-260215&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a hardcoded fallback key so the endpoint never 500s, even if the env var disappears&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I pushed, the build took 50 minutes (Cloudflare Pages, 8000+ files, single-threaded wrangler — story for another day), and within an hour I had all 8 endpoints live.&lt;/p&gt;

&lt;p&gt;I tested every single one. All 8 returned real data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned (so you do not have to learn it the same way)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Never depend on a single API key for everything.&lt;/strong&gt;&lt;br&gt;
The most important change was not the migration — it was adding a hardcoded fallback key inside the function. Now even if the env var disappears, the endpoint keeps working. Belt and suspenders. It is also why I sleep at night.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pick providers who will be around next year.&lt;/strong&gt;&lt;br&gt;
The best API is the one that is still up 12 months from now. Big, well-funded, with a real dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Build for the panic, not the calm.&lt;/strong&gt;&lt;br&gt;
Every one of my functions was structured the same way: try the provider, catch the error, return a graceful fallback. That structure is what let me swap providers in a night without rewriting anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Test your fixes at 2am.&lt;/strong&gt;&lt;br&gt;
I ran a script that POSTed real test bodies to every endpoint. 5 out of 8 passed in 30 seconds. 3 out of 8 timed out at 35 seconds — the actual responses took 50-65 seconds. If I had trusted the 30-second timeout, I would have shipped a broken site.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is on my site now
&lt;/h2&gt;

&lt;p&gt;If you want to see the AI tools that survived the migration, they are all here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-name-generator/" rel="noopener noreferrer"&gt;AI Name Generator&lt;/a&gt; — names with meaning and origin&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/concept-explain/" rel="noopener noreferrer"&gt;Concept Explainer&lt;/a&gt; — explain anything simply&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/idea-to-action/" rel="noopener noreferrer"&gt;Idea to Action&lt;/a&gt; — turn a vague idea into a plan&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/tone-changer/" rel="noopener noreferrer"&gt;Tone Changer&lt;/a&gt; — rewrite in any tone&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/task-breakdown/" rel="noopener noreferrer"&gt;Task Breakdown&lt;/a&gt; — turn a goal into steps&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/seo-miner/" rel="noopener noreferrer"&gt;SEO Miner&lt;/a&gt; — keywords with intent and heat&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-workflow/" rel="noopener noreferrer"&gt;AI Workflow&lt;/a&gt; — multi-step workflows&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://korelyy.com/en/tool/ai-recommend/" rel="noopener noreferrer"&gt;AI Recommend&lt;/a&gt; — find the right tool for the job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All running in your browser, no signup. The whole collection is at &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;korelyy.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what about you?
&lt;/h2&gt;

&lt;p&gt;Have you ever had a single point of failure take down your whole product at the worst possible time? How did you fix it — and more importantly, what did you do afterwards to make sure it could not happen again?&lt;/p&gt;

&lt;p&gt;I am asking because I am still thinking about #4 above. There is a more elegant version of "hardcoded fallback" that I have not built yet, and I bet someone reading this has already built it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I built a free emoji mixer that runs entirely in your browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Thu, 30 Jul 2026 18:25:21 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-a-free-emoji-mixer-that-runs-entirely-in-your-browser-5488</link>
      <guid>https://dev.to/korelyy/i-built-a-free-emoji-mixer-that-runs-entirely-in-your-browser-5488</guid>
      <description>&lt;p&gt;I kept seeing those "smash two emojis together" sites and noticed something: most of them upload your image to a server. Even when the math is just stacking pixels.&lt;/p&gt;

&lt;p&gt;So I built my own. It runs entirely in the browser. No uploads, no signup, no paywall.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick up to 4 emojis from a searchable grid&lt;/li&gt;
&lt;li&gt;The tool uses the Unicode emoji list and renders each one to a canvas&lt;/li&gt;
&lt;li&gt;It composites them with offset, scaling, and rotation&lt;/li&gt;
&lt;li&gt;You get one PNG to download&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing is about 200 lines of JavaScript. No backend. No API. No tracking. The emoji data ships with the page.&lt;/p&gt;

&lt;p&gt;If you want to see it: &lt;a href="https://korelyy.com/en/tool/emoji-mixer/" rel="noopener noreferrer"&gt;https://korelyy.com/en/tool/emoji-mixer/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few things I learned while building it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Most "client-side" tools still hit a server.&lt;/strong&gt; The hidden cost is usually analytics, asset CDN, or auth. Real client-side means the page works offline after first load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Canvas compositing has hidden gotchas.&lt;/strong&gt; Emoji rendering across platforms gives different base images. Apple's cat emoji is not the same as Google's. I default to the system font the user already has, so the result feels native.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The fun tools spread faster than the useful ones.&lt;/strong&gt; My calculator for container shipping has solid keyword potential. The emoji mixer gets 10x the social shares. Build accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Browser-only also means privacy by default.&lt;/strong&gt; A user pasting sensitive content into a "redact PDF" tool shouldn't have to trust the server. Local-only removes that question entirely.&lt;/p&gt;

&lt;p&gt;I have about 50 small tools like this on my site now. Each one is the answer to a "I just need to do X real quick" moment. Some get used once a day, some once a year. Both are worth building if the alternative is opening an app and signing up.&lt;/p&gt;

&lt;p&gt;If you want to see the full set: &lt;a href="https://korelyy.com/en/" rel="noopener noreferrer"&gt;https://korelyy.com/en/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The video showing it in action: &lt;a href="https://www.youtube.com/shorts/riFG3Jq8-7c" rel="noopener noreferrer"&gt;https://www.youtube.com/shorts/riFG3Jq8-7c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's a "quick task" tool you wish existed but you keep avoiding because it needs a login?&lt;/p&gt;

</description>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Got 1,000+ URLs Indexed for a Solo-Built Tool Site ??Without Paid Tools</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Thu, 30 Jul 2026 03:18:31 +0000</pubDate>
      <link>https://dev.to/korelyy/how-i-got-1000-urls-indexed-for-a-solo-built-tool-site-without-paid-tools-c0b</link>
      <guid>https://dev.to/korelyy/how-i-got-1000-urls-indexed-for-a-solo-built-tool-site-without-paid-tools-c0b</guid>
      <description>&lt;h1&gt;
  
  
  How I Got 1,000+ URLs Indexed for a Solo-Built Tool Site ??Without Paid Tools
&lt;/h1&gt;

&lt;p&gt;I run korelyy.com ??a free online tool site with 1,000+ tools across 6 languages.&lt;/p&gt;

&lt;p&gt;Getting indexed was harder than building the site.&lt;/p&gt;

&lt;p&gt;Here's the exact SEO workflow I used to get 1,000+ URLs indexed in Google, Bing, and Yandex ??as a solo developer with zero budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  The indexing problem
&lt;/h2&gt;

&lt;p&gt;A tool site has a fundamentally different URL structure than a blog. Each tool is a page. Each language is a separate URL. A 1,000-tool site in 6 languages = 6,000+ potential URLs.&lt;/p&gt;

&lt;p&gt;Bloggers write 50 posts a year. Tool sites ship 1,000 pages on day one.&lt;/p&gt;

&lt;p&gt;The standard SEO playbook doesn't work here. You can't "write quality content" for a Base64 decoder or a PNG compressor. The content is the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did (in order of effectiveness)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Sitemap architecture
&lt;/h3&gt;

&lt;p&gt;One sitemap index ??6 language-specific sitemaps (en, zh, es, hi, fr, ar). Each language sitemap contains ~185 tool URLs.&lt;/p&gt;

&lt;p&gt;Key lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't use one giant sitemap.&lt;/strong&gt; Split by language or category. Google processes them in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include the lastmod field.&lt;/strong&gt; Even if it's the build date, it signals freshness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit each language sitemap to the corresponding Google Search Console property.&lt;/strong&gt; The hreflang tags in sitemaps help Google understand language targeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Google Search Console
&lt;/h3&gt;

&lt;p&gt;GSC accepted my sitemap and started indexing within 48 hours.&lt;/p&gt;

&lt;p&gt;The critical setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add each language variant as a separate property (or use the International Targeting report)&lt;/li&gt;
&lt;li&gt;Submit the sitemap index URL, not individual sitemaps&lt;/li&gt;
&lt;li&gt;Use the URL Inspection tool to manually request indexing for your most important pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. IndexNow (Bing + Yandex)
&lt;/h3&gt;

&lt;p&gt;IndexNow is the fastest way to get URLs indexed. It's supported by Bing, Yandex, and now Seznam.&lt;/p&gt;

&lt;p&gt;The setup is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a key file and place it at /.well-known/ or your site root&lt;/li&gt;
&lt;li&gt;Submit URL batches via HTTP POST to &lt;a href="https://api.indexnow.org/indexnow" rel="noopener noreferrer"&gt;https://api.indexnow.org/indexnow&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I submitted all 1,000+ URLs in batches of 10,000 (the max per request). Bing picked them up within hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. hreflang and JSON-LD
&lt;/h3&gt;

&lt;p&gt;Every tool page has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hreflang link tags&lt;/strong&gt; in the  pointing to all 6 language variants&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD structured data&lt;/strong&gt; with WebApplication schema for tool pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn't directly help indexing, but it dramatically improves how search engines understand and display your pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The hard truth about 404s
&lt;/h3&gt;

&lt;p&gt;After generating the full sitemap, I found 47 URLs that returned 404s ??broken categories, removed tools, URL encoding issues.&lt;/p&gt;

&lt;p&gt;Fix: set up a Cloudflare Pages function to catch and redirect them, or fix the routes in the static build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pinging sitemap URLs directly&lt;/strong&gt; (Google's ping endpoint is deprecated, Bing's returned 410)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relying only on internal linking&lt;/strong&gt; ??you still need sitemaps for deep pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social media shares&lt;/strong&gt; ??great for traffic, negligible for indexing at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The results after 3 weeks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Indexed URLs (GSC)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;91+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bing indexed&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;85+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yandex indexed&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;70+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total sitemap URLs&lt;/td&gt;
&lt;td&gt;240&lt;/td&gt;
&lt;td&gt;1,110&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set up sitemaps before launch&lt;/strong&gt;, not after. Indexing delay cost me the first week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use IndexNow from day one.&lt;/strong&gt; It's the fastest path to Bing/Yandex coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix 404s before submitting.&lt;/strong&gt; Every broken URL in your sitemap wastes crawl budget.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;?? &lt;strong&gt;&lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/strong&gt; ??1,000+ free tools, 6 languages, all client-side. No uploads, no signups.&lt;/p&gt;

&lt;p&gt;If you're building a tool site or working on SEO for a content-heavy project, I'm happy to answer questions below.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>indiehacker</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why I Only Build Tools That Run in Your Browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 29 Jul 2026 23:22:23 +0000</pubDate>
      <link>https://dev.to/korelyy/why-i-only-build-tools-that-run-in-your-browser-2ke</link>
      <guid>https://dev.to/korelyy/why-i-only-build-tools-that-run-in-your-browser-2ke</guid>
      <description>&lt;p&gt;There's a debate all over X right now: is software dead? Big AI is eating everything, so what's left for solo builders?&lt;/p&gt;

&lt;p&gt;My honest take is the opposite. I've never felt more alive doing this. The catch: I don't build big software. I build tiny tools that run entirely in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "runs in your browser" means
&lt;/h2&gt;

&lt;p&gt;You open a page, and the tool runs on your own device. No login, no signup, no subscription, no uploads. What you type never leaves your browser, and there's no server quietly logging it. Close the tab and nothing is left behind.&lt;/p&gt;

&lt;p&gt;For a builder, this is almost cheating: no database to babysit, no user account system, no monthly server bill, no 3am panic about a data breach. For the user it's even simpler: open it, use it, leave.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm betting on this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Privacy is real.&lt;/strong&gt; A lot of free online tools quietly upload your files to their servers. A browser-only tool literally cannot do that, because there's no server catching your data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; No round trips. Click and the result is there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability.&lt;/strong&gt; No backend means no server-is-down-whole-site-is-dead. Many tools even work offline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low friction.&lt;/strong&gt; The signup wall scares off most people who wanted to use your tool. Remove it and the rest actually stick around.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So what am I after
&lt;/h2&gt;

&lt;p&gt;Honestly, I'm not sure this scales in the startup sense. But I keep noticing a pattern: the things people actually open every day aren't the feature-stuffed platforms. They're the "one thing that just runs and solves my one small problem" tools.&lt;/p&gt;

&lt;p&gt;The big-software lane is crowded. But the small, useful, open-and-go lane has never been this wide open.&lt;/p&gt;

&lt;p&gt;So I just keep planting tools there, one at a time. Some get ignored. Some get used daily by way more people than I expected. I don't know where it ends, but I know I love doing it.&lt;/p&gt;

&lt;p&gt;I've been building a growing collection of these browser-based tools over at korelyy.com — always happy to trade notes with other builders.&lt;/p&gt;

&lt;p&gt;If you're building something similar, or you've got a "wish a little tool existed for this" itch, come say hi in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I built a multi-language privacy-first online tool suite, everything runs locally inside your browser</title>
      <dc:creator>CarsonJ</dc:creator>
      <pubDate>Wed, 22 Jul 2026 12:36:43 +0000</pubDate>
      <link>https://dev.to/korelyy/i-built-a-multi-language-privacy-first-online-tool-suite-everything-runs-locally-inside-your-b94</link>
      <guid>https://dev.to/korelyy/i-built-a-multi-language-privacy-first-online-tool-suite-everything-runs-locally-inside-your-b94</guid>
      <description>&lt;h1&gt;
  
  
  I built a multi-language privacy-first online tool suite, everything runs locally inside your browser
&lt;/h1&gt;

&lt;p&gt;If you’ve used random free online tools recently, you’ve probably run into the same frustrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have to register an account just for a one-time quick task&lt;/li&gt;
&lt;li&gt;Annoying ads and forced watermarks on your exported files&lt;/li&gt;
&lt;li&gt;You upload private photos, PDFs or text data to unknown third-party servers&lt;/li&gt;
&lt;li&gt;Many tools only support English, no multi-language interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why I spent months building &lt;strong&gt;Korelyy Tools&lt;/strong&gt;, a collection of everyday web utilities with a simple core rule:&lt;br&gt;
&lt;strong&gt;All processing happens locally in your browser. Your files never leave your device.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s inside the toolkit
&lt;/h2&gt;

&lt;p&gt;Right now the site includes common utilities for regular users and developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image compression &amp;amp; conversion&lt;/li&gt;
&lt;li&gt;QR Code generator &amp;amp; reader&lt;/li&gt;
&lt;li&gt;PDF basic tools&lt;/li&gt;
&lt;li&gt;Emoji mixer&lt;/li&gt;
&lt;li&gt;JSON formatter / validator&lt;/li&gt;
&lt;li&gt;AI text writing helper&lt;/li&gt;
&lt;li&gt;More dev-focused small utilities on the roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Core design choices I stuck to
&lt;/h3&gt;

&lt;p&gt;✅ No signup, no login required for any tool&lt;br&gt;
✅ Zero watermarks on all outputs&lt;br&gt;
✅ Client-side computation: No file uploads to backend servers&lt;br&gt;
✅ Multi-language support: English, Chinese, Spanish, French, Hindi, Arabic&lt;br&gt;
✅ Static site built on Next.js, low long-term hosting costs&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical challenges I ran into
&lt;/h2&gt;

&lt;p&gt;Building fully client-side tools wasn’t as straightforward as I expected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser memory limits&lt;/strong&gt;&lt;br&gt;
Large images and multi-page PDFs can easily trigger tab crashes. I added chunk processing to avoid out-of-memory errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web Worker performance&lt;/strong&gt;&lt;br&gt;
Heavy tasks block the main thread, so I moved compression and document parsing into Web Workers to keep the UI responsive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-language i18n management&lt;/strong&gt;&lt;br&gt;
Maintaining translation strings for six languages adds a lot of repetitive work. I’m still optimizing how I manage localization files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SEO for dozens of independent tool pages&lt;br&gt;
Each small tool needs its own meta title, description and structured content to rank on search engines. It’s a slow ongoing process.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Current status &amp;amp; growth
&lt;/h2&gt;

&lt;p&gt;After launching publicly, the site hit around &lt;strong&gt;1.2k pageviews in the first 28 days&lt;/strong&gt; with zero paid ads. Most traffic comes from organic search at the moment.&lt;/p&gt;

&lt;p&gt;There’s still a long feature list I want to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more developer utilities&lt;/li&gt;
&lt;li&gt;Improve mobile responsive layout&lt;/li&gt;
&lt;li&gt;Expand more language translations&lt;/li&gt;
&lt;li&gt;Optimize bundle size for faster initial load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m actively collecting feedback to prioritize new tools and improvements.&lt;/p&gt;

&lt;p&gt;If you want to test it out: &lt;a href="https://korelyy.com" rel="noopener noreferrer"&gt;https://korelyy.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts:&lt;br&gt;
What free web tools do you wish existed without signups, ads or data collection?&lt;br&gt;
What features should I build next?&lt;br&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%2F3z7wx4aiv5mpoyrlqs0h.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%2F3z7wx4aiv5mpoyrlqs0h.jpg" alt=" " width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
