MSW Has a Free API Mocking Framework — Stop Using Custom Mock Servers

You’re probably mocking APIs wrong. Custom mock servers, intercepting fetch globally, hardcoding responses — all fragile, all pain.

MSW (Mock Service Worker) fixes this at the network level.

What is MSW?

MSW intercepts HTTP requests at the network level using Service Workers (browser) or custom interceptors (Node.js). Your application code doesn’t know it’s being mocked. That’s the point.

Why MSW Changes Everything

1. Network-Level Interception

import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' },
    ]);
  }),

  http.post('/api/users', async ({ request }) => {
    const user = await request.json();
    return HttpResponse.json({ id: 3, ...user }, { status: 201 });
  }),
];

Your fetch(), axios, ky — all intercepted. No code changes needed.

2. Same Mocks for Browser AND Node.js

// Browser (Storybook, dev server)
import { setupWorker } from 'msw/browser';
const worker = setupWorker(...handlers);
worker.start();

// Node.js (tests, SSR)
import { setupServer } from 'msw/node';
const server = setupServer(...handlers);
server.listen();

Write mocks once. Use everywhere.

3. Request Handlers That Feel Natural

import { http, HttpResponse } from 'msw';

const handlers = [
  // Path parameters
  http.get('/api/users/:id', ({ params }) => {
    return HttpResponse.json({ id: params.id, name: 'Alice' });
  }),

  // Query parameters
  http.get('/api/search', ({ request }) => {
    const url = new URL(request.url);
    const query = url.searchParams.get('q');
    return HttpResponse.json({ results: [`Result for ${query}`] });
  }),

  // Error responses
  http.get('/api/protected', () => {
    return HttpResponse.json(
      { error: 'Unauthorized' },
      { status: 401 }
    );
  }),

  // Network errors
  http.get('/api/unstable', () => {
    return HttpResponse.error();
  }),
];

4. Perfect for Testing

import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const server = setupServer(...handlers);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('shows user profile', async () => {
  // Override for this specific test
  server.use(
    http.get('/api/users/1', () => {
      return HttpResponse.json({ id: 1, name: 'Test User', role: 'admin' });
    })
  );

  render(<UserProfile userId="1" />);
  expect(await screen.findByText('Test User')).toBeInTheDocument();
});

test('handles API errors gracefully', async () => {
  server.use(
    http.get('/api/users/1', () => {
      return HttpResponse.json({ error: 'Not found' }, { status: 404 });
    })
  );

  render(<UserProfile userId="1" />);
  expect(await screen.findByText('User not found')).toBeInTheDocument();
});

5. WebSocket Mocking

import { ws } from 'msw';

const chat = ws.link('wss://api.example.com/chat');

export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));

    client.addEventListener('message', (event) => {
      client.send(JSON.stringify({
        type: 'echo',
        data: event.data
      }));
    });
  }),
];

MSW vs Other Mocking Approaches

MSW Jest mocks Nock JSON Server
Level Network Module HTTP Server
Browser Yes No No Yes
Node.js Yes Yes Yes Yes
Framework agnostic Yes Jest only Node only Yes
WebSocket Yes No No No
No code changes Yes Requires import changes Yes Yes

Getting Started

npm install msw --save-dev
npx msw init public/ --save

Create src/mocks/handlers.ts, define your handlers, and you’re done.

The Bottom Line

MSW is the standard for API mocking in 2026. Network-level interception, cross-environment support, and WebSocket mocking make it the tool your test suite has been missing.

Building data-intensive applications? I create custom web scraping and data extraction tools. Check out my Apify actors or email [email protected].

We analyzed 10,000 voice AI calls. The LLM was rarely the problem.

We built Dograh OSS, an open-source voice AI platform. When we started, we assumed most failures would come from the LLM – bad answers, missed intent, prompt edge cases. So we spent a lot of early effort there.

Then we looked at the data. We ran automated QA where an LLM reviews every turn in every call and tags what went right and wrong, and we spent hours listening to calls ourselves. Across roughly 10,000 calls spanning customer support, appointment booking, and lead qualification, the failure picture looked nothing like what we expected.

The problems that showed up again and again were about the phone call as a medium. Timing, audio physics, and infrastructure designed decades before LLMs existed.

Here is what we found, roughly ranked by frequency.

Failure area Share Primary driver
STT / word error rate ~38% Low-quality telephony audio and accent variation
First-8-second chaos ~34% Greeting latency, barge-in, variable user behavior
Interruption handling ~28% Filler words breaking flow, context switching
Extended silence ~22% Users distracted, fetching info, handing off phone
Tool call latency ~19% LLM turns plus external API latency
LLM failure modes ~15% Hallucinations, instruction drift, latency trade-offs
Broken escalation ~11% No clear human handoff path

These categories overlap. A lot of bad calls had two or three of these compounding each other.

STT is worse than you think

STT failures were the single biggest contributor to broken calls, and the one most consistently underestimated by teams building voice AI for the first time.

Standard telephony runs at 8 kHz audio. That is genuinely low quality. It strips away acoustic detail that helps distinguish consonants, so “schedule” becomes “school” in a transcript and “Sunday” comes through as “someday.” Add background noise, speakerphone, or a non-native accent and word error rates climb fast.

The thing about WER is that errors compound. “I need to school my appointment for someday” should be understood as “I need to schedule my appointment for Sunday,” and a well-prompted LLM will figure that out. When three or four words are garbled in the same turn though, contextual inference falls apart. We saw calls where entire turns came through as near-gibberish.

There is also a dimension STT completely misses. Transcription captures words but it does not capture how those words are said. A frustrated “fine” and a genuinely agreeable “fine” are two very different things, but they look identical in a transcript. Tone helps disambiguate words that sound similar. When a caller sounds confused or hesitant, a human listener picks up on that and adjusts. STT gives you a flat string of text and the LLM works with it blind.

No STT provider has uniform accuracy across all accents either. The gap between a provider’s accuracy on American English versus Nigerian English or heavily accented Spanish can be 15 to 25 percentage points. If your users call from diverse regions, picking one STT provider and moving on is going to hurt you.

Two mitigations made a real difference in our testing. First, adding a custom vocabulary to your STT engine – and I mean beyond domain jargon. If you are building an order management bot, add the common words your callers actually say: “order,” “ID,” “payment,” “cancel,” “account,” “address.” Thirty to forty frequently used words. The STT engine listens for these with extra weight and it meaningfully reduces errors on the terms that matter most.

Second, tell the LLM to expect transcription errors. A single line in your system prompt acknowledging that the caller’s words may contain transcription noise, and asking the model to use contextual reasoning before responding, reduces the downstream impact of STT failures significantly. The LLM stops treating garbled transcripts as literal input and starts being smarter about what the caller probably meant.

The first 8 seconds are where calls die

About a third of all problematic calls failed before the real conversation even started.

A lot happens in those first 8 to 10 seconds. Callers are still deciding whether they want to engage. Many have not fully shifted their attention to the call. Some are already talking before the bot finishes its greeting, and others wait much longer than expected, unsure whether the silence means the system is broken. This is also the window where callers most frequently realize they are talking to a bot, and many immediately start testing it – interrupting, asking off-script questions, being deliberately vague. The variance in behavior is just much higher here than at any other point in the call.

Greeting latency makes everything worse. A gap of more than a second or two between the call connecting and the first word of audio is enough for many callers to assume things are broken and hang up. Pre-generating and caching your greeting audio instead of synthesizing it fresh every time removes an entire class of failures here.

What works: keep greetings short, under six seconds. Consider disabling barge-in for just the first 3 to 4 seconds if your greeting contains information the caller needs to hear. Re-enable interruption after that. The period where barge-in causes the most problems is right at the start.

In Dograh, each workflow node has its own “Allow Interruption” toggle, so you can switch off interruption on the starting node for a short introduction and re-enable it for the rest of the conversation.

Interruptions, silence, and dead air

Most barge-in documentation focuses on detecting when a user starts speaking and stopping the TTS output. That part is reasonably well solved. The harder problem is what happens to the conversation after the interruption.

One pattern we saw constantly: a caller says “uh huh” or “yeah” while the bot is talking. The bot interprets this as a genuine turn, stops speaking, and tries to process it as new user input. The LLM produces a response to what is essentially a non-sentence and the conversation breaks. The caller has to re-explain what they wanted.

A related pattern involves context switching – a caller interrupts to ask “wait, does that include weekends?” The bot handles the question fine but loses track of what it was explaining before. The original task gets dropped without resolution.

Both problems are about how interruption events are handled in the conversation state. The fix is designing explicit logic for what happens after an interruption. Differentiate between filler sounds and substantive speech, and track unresolved conversational threads so the bot can come back to them.

Silence is closely related. Real callers go quiet for perfectly legitimate reasons – checking an email for an order ID, handing the phone to someone else, looking something up. A caller fetching information might go quiet for 20 to 40 seconds. Most voice AI systems interpret this as confusion or abandonment and respond with prompts or just hang up.

A graduated response works much better: a brief neutral filler after 5 seconds, a gentle “still there?” check at 15 seconds, a real choice at 45 seconds (“I can hold, or you are welcome to call back”), and a graceful close with callback instructions only after 90 seconds or more.

Tool call latency creates its own kind of dead air

When a voice agent needs to look something up in a CRM or check a calendar slot, a tool call gets triggered. In practice that means at least one additional LLM turn to interpret the result, plus the external API latency. The total gap can easily reach 3 to 5 seconds, and callers at that point genuinely don’t know if the call is still alive.

We are adding a “playback speech” feature in Dograh that lets you configure a pre-recorded audio clip to play while a tool call executes. This fills the silence without the LLM having to generate a response and it keeps the caller engaged. Beyond that, pre-fetching data you know will be needed at call start – account details, prior call history, caller ID lookups – keeps common tool calls out of the live response path entirely.

LLM failures and broken escalation

LLM failures in production voice AI are real but probably smaller than you would expect. Hallucination gets the most attention but it accounts for a smaller share of bad calls than the quieter failures. Models stop following instructions partway through long calls. They generate empty responses that cause the bot to say nothing at all. They produce answers that are technically coherent but completely disconnected from the previous turn.

The trade-off between model size and latency matters here too. Smaller models respond faster, which helps perceived call quality, but they follow complex instructions less reliably. Larger models handle nuanced prompts better but their response latency feeds right back into the dead-air problem.

Escalation failures have a lower frequency but they are the most consequential category on this list. The callers asking for a human almost always have the hardest, most urgent problems. They have already tried self-service and it didn’t work. When the bot can’t detect they want to escalate – because they phrased it in a way the intent detection doesn’t recognize – or when the escalation path drops the context so the human agent starts from scratch, that caller’s experience is about as bad as it gets.

Escalation should be a first-class destination in every workflow. The phrases callers use to ask for a human are wildly more varied than any training set anticipates, and the transfer needs to carry the full conversation transcript to the receiving agent.

The pattern

Voice AI breaks at transitions. The first seconds of a call, the moment a user interrupts, the gap while a tool is running, the point where a caller needs a human. These are the edges where the system’s assumptions about how conversations work meet how people actually behave on phone calls.

Teams that focus almost entirely on LLM response quality and treat these transitions as secondary concerns tend to ship agents that sound good in demos but disappoint in production. The calls that held up well in our data were the ones with the most deliberate handling of everything that happens between LLM responses.

We are building Dograh as the open-source alternative to Vapi, Retell, and Bland. No per-minute fees, no vendor lock-in, deploy on your own infra. Ask anny queries

Star us on GitHub | Try the cloud version

Never Used RSS? Start Here.

person reading on laptop with coffee in calm workspace

You open your favorite app to catch up on the news. Thirty minutes later, you’ve watched two unrelated videos, scrolled past a dozen ads, and still haven’t read the article your coworker mentioned. Sound familiar?

Algorithmic feeds are designed to maximize engagement, not to inform you. They decide what you see, when you see it, and how long you stay. The result is a reading experience that feels busy but leaves you less informed. There’s a better way, and it’s been around for over two decades.

RSS — Really Simple Syndication — is a quiet technology that puts you back in control. No algorithms. No ads. No tracking. Just the content you asked for, delivered the moment it’s published. If you’ve never tried it, this guide will have you set up in under ten minutes.

person reading on laptop with coffee in calm workspace

Photo by ubeyonroad on Unsplash

What Is RSS, Actually?

RSS stands for Really Simple Syndication. It’s an open standard that lets websites publish updates in a structured format — a small file that lists the latest articles, posts, or episodes. When you subscribe to a site’s RSS feed, your reader checks that file periodically and shows you anything new.

Think of it like email subscriptions, but without the email. You don’t hand over your address. You don’t get marketing messages. You just see the content. According to Wikipedia’s overview of RSS, the format dates back to 1999 and remains one of the most widely supported syndication standards on the web.

Most websites you already read have an RSS feed. News outlets, blogs, magazines, government sites, YouTube channels, podcasts, and even some social media accounts publish feeds. You just need something to read them with.

The magic of RSS is its simplicity. There’s no company controlling the pipe between you and the publisher. No one is inserting sponsored content or reordering your timeline to boost engagement metrics. What gets published is what you get. In that order. Every time.

Why RSS Deserves a Comeback

You might wonder why you’d bother with a technology from the early 2000s. The answer is that the problems RSS solves have only gotten worse.

Social platforms increasingly gate content behind recommendation engines. A study published by the Reuters Institute for the Study of Journalism found that a growing share of people feel they have little control over the news they encounter online. Algorithmic curation means you might miss important reporting from a source you follow simply because the platform decided something else would get more clicks.

RSS eliminates that problem entirely. Every article, every post, every update shows up in your reader chronologically. You choose your sources. You see everything they publish. You decide what to read and what to skip.

It’s also private

When you subscribe to an RSS feed, the publisher doesn’t know who you are. There’s no account, no tracking pixel, no behavioral profile. Your reading habits stay yours. In a decade defined by data privacy concerns, that matters more than most people realize.

And it’s fast

No ads loading. No cookie banners. No autoplay videos. RSS delivers clean text and images. Your reader renders content instantly, which means you spend time reading instead of waiting.

Setting Up Your First Feed Reader

Getting started with RSS takes about five minutes. Here’s the process, step by step.

Step 1: Choose a feed reader

A feed reader is the app that collects and displays your RSS subscriptions. There are many options — web-based, desktop, and mobile. Some popular choices in 2026 include Feedly, Inoreader, NetNewsWire (free and open source for Mac and iOS), and Miniflux for self-hosters.

EchoLive also includes a full-featured feeds inbox with support for up to 100 free feeds, auto-refresh, keyboard shortcuts, and built-in audio generation. If you want to read and listen to your feeds in one place, it’s worth a look.

Pick whatever fits your workflow. The beauty of RSS is that you’re never locked in — your subscriptions are portable.

Step 2: Find feeds to subscribe to

Most websites have an RSS feed even if they don’t advertise it. Here’s how to find them:

  • Look for the RSS icon. Some sites display an orange RSS icon, usually in the header or footer.
  • Check the URL. Try adding /feed, /rss, or /atom.xml to the end of a website’s address. For example, example.com/feed often works for WordPress sites.
  • Use your reader’s search. Most feed readers let you paste a website URL and will auto-detect the feed.
  • Try a feed discovery tool. EchoLive offers semantic search and a curated category browser to help you find feeds by topic. Describe what you’re interested in, and subscribe in seconds.

Start small. Pick five to ten sources you genuinely want to follow — your favorite news outlet, a blog you always come back to, maybe a niche publication in your field.

Step 3: Organize with folders or tags

Once you’ve added a handful of feeds, group them. Most readers support folders or categories. A simple structure works best:

  • News — Major outlets and breaking coverage
  • Tech — Industry blogs and product updates
  • Personal — Friends’ blogs, hobby sites, creative writing
  • Work — Industry publications, company blogs, research

Don’t over-organize at the start. You can always restructure later as your collection grows.

Step 4: Set a reading rhythm

RSS works best as a daily habit, not a firehose. Check your reader once or twice a day. Scan headlines. Open what interests you. Mark the rest as read and move on. The goal isn’t to read everything — it’s to have a curated source of content that respects your attention.

Building a Feed Collection That Works

The biggest mistake new RSS users make is subscribing to too many feeds at once. You end up with hundreds of unread items, feel overwhelmed, and quit. Here’s how to avoid that.

Start with ten feeds or fewer

Quality over quantity. Choose sources where you’d read most of what they publish. If a site posts twenty articles a day and you only care about one, that feed will generate noise. Look for publications with a manageable posting frequency — a few articles per week is ideal for most personal readers.

Prune regularly

Every few weeks, glance at your feed list. If you’re consistently skipping a source, unsubscribe. RSS should feel like a curated magazine, not an obligation. There’s no penalty for removing a feed, and you can always add it back.

Mix your sources

A good feed collection balances breadth and depth. Include a major news outlet for general awareness, niche blogs for deep expertise, and maybe a few unexpected sources — a webcomic, a cooking blog, a local government feed — to keep things interesting.

Import existing subscriptions

If you’re switching from another reader or already have a list of feeds, most readers support OPML — a standard file format for feed lists. You can import OPML files into virtually any reader and have your entire collection set up instantly.

Going Further: Audio, Discovery, and Daily Habits

Once you’ve settled into RSS, you might want to go beyond reading. Here are a few ways to level up.

Listen to your feeds

Not every article needs your full visual attention. Commuting, exercising, or cooking are perfect times to catch up on your feeds by listening instead of reading. You can turn RSS into audio using text-to-speech tools that convert articles into natural-sounding audio. EchoLive’s feeds inbox, for example, offers built-in audio generation with 630+ neural voices — pick a voice, hit play, and follow along with word-level sync highlighting.

Build a daily brief

Instead of checking feeds manually, some tools can compile a curated audio briefing from your subscriptions. EchoLive’s Daily Brief combines your feeds and trending stories into a scored, skippable audio digest with transcript view and date navigation. It’s like having a personal news anchor who only covers topics you care about.

Explore trending content alongside your feeds

RSS is great for following specific sources, but sometimes you want to discover what’s happening more broadly. EchoLive’s Pulse feature surfaces real-time trending stories from across the web, consolidated by topic. It’s a nice complement to your curated feed list — algorithmic discovery on your terms, not a platform’s.

Share what you find

One of the underrated joys of RSS is stumbling on articles worth sharing. Save the best pieces to collections, highlight key passages, and share them with friends or colleagues. Good content is meant to be passed along.

Take Control of What You Read

RSS isn’t complicated. It isn’t outdated. It’s a quiet, powerful tool that gives you something increasingly rare in 2026 — full control over your information diet. No algorithm stands between you and the sources you trust.

Start with five feeds today. Give it a week. You’ll wonder how you ever relied on a timeline that someone else curated for you. And if you want to read, listen, and organize your feeds in one place, EchoLive is a good place to start.

Originally published on EchoLive.

I got tired of ad-filled, fake-button TikTok Downloaders, so I built my own (Minimalist & Ad-Free)

I got tired of ad-filled, fake-button TikTok Downloaders, so I built my own (Minimalist & Ad-Free)

Let’s be honest. Have you ever tried searching for a “TikTok Video Downloader” on Google?

The search results are a UX nightmare. You click on a link, and you are immediately bombarded with:

  • 3 different popup windows.
  • 5 buttons that say “DOWNLOAD NOW” (4 of which are malware ads).
  • A blindingly bright, cluttered interface from 2010.

As a web developer, this frustrated me. The internet doesn’t need another spammy download site. It needs tools that respect the user’s time and eyes.

So, I spent my recent weekends building TikSpider.

What is TikSpider?

TikSpider.com is a blazing fast, web-based tool to download TikTok videos without watermarks, extract audio (MP3), and save TikTok Stories.

But more importantly, it’s an experiment in bringing the “Less is More” design philosophy into a space that is notoriously chaotic.

🎨 The Design Philosophy: Dark Mode & Frosted Glass

Most utility tools overlook design. I wanted to build something that feels like a native, premium app rather than a sketchy script.

I stripped away everything unnecessary. No sidebars, no sticky banner ads, no confusing navigation. Just a single, perfectly centered input field.

To make it easy on the eyes (especially for late-night scrollers), the entire UI is built around a pure Dark Mode aesthetic. I used frosted glass (glassmorphism) effects for the main interactive panels. The result is a UI that feels cold, sharp, and highly technical—exactly what a “spider” fetching data should feel like.

⚙️ Under the Hood & Features

Building this wasn’t just about making it look pretty; it had to be functional and fast.

Here is what it currently handles perfectly:

  1. No Watermark Video Extraction: It parses the official URL and fetches the clean, unwatermarked HD MP4 stream directly.
  2. TikTok to MP3: A lot of users just want the trending audio. The tool isolates and extracts the audio track instantly.
  3. TikTok Stories: Stories disappear in 24 hours. TikSpider bypasses the app restrictions to let you save them locally.
  4. Photo Slideshows: It also cleanly extracts HD images from TikTok photo swipe-posts.

🌍 The Next Challenge: Global i18n and SEO Architecture

One of the most interesting technical challenges I’m tackling right now is scaling this globally. TikTok is massive in regions like Indonesia, Latin America, and Europe.

Instead of relying on auto-translate plugins, I’m building a robust hreflang based multi-language architecture (deploying native sub-directories like /es/, /id/, etc.) to serve localized versions without compromising the core Next.js/Nuxt caching performance or the minimalist UI layout.

🚀 Try it out and roast my UI!

I built this tool for users who appreciate clean, efficient software. It’s completely free, requires no installation, and will remain ad-free in its core downloading experience.

Check it out here: TikSpider.com

I would absolutely love the Dev.to community’s feedback.

  • How does the frosted glass dark UI feel on your device?
  • Did it parse your links fast enough?
  • Any edge cases where the spider failed to fetch?

Drop a comment below. I’ll be reading and replying to everything! 🕷️