Voice input for your product, on your user's own computer where it can be
Somebody has asked you for voice input. A support desk wants agents to talk into the reply box, a field service app wants notes dictated with gloves on, an internal tool wants a bug described rather than typed. Every way of building it has the same problem underneath: the moment you accept audio, you are responsible for it.
Free, with no account and no sign-in.
The browser's own speech recognition sends the audio to the browser vendor. A speech API makes you a processor of your customers' voice recordings, billed by the minute and defended in every security review. A model inside your own app is a couple of hundred megabytes and an accuracy problem you own forever.
There is a fourth option, and it is the reason this page exists: let the copy of Deixis on the user's machine do it. Your page asks for words; the recognition happens on their processor; the words arrive in your field. While Deixis on the user's computer is running and connected to your site, no audio reaches your servers, ours, or any cloud, because it never leaves the computer it was spoken on. Otherwise (no Deixis, not yet connected to you, or not running), the drop-in mic has a cloud route: the recording goes through Deixis to Cloudflare's speech model and comes back as text. We keep neither the recording nor the words, the audio never touches your servers, and the user is told every time, beside the mic. Try it live on our own page, or read the partner programme for what it costs and what partners earn.
Three lines: the drop-in mic
<script src="https://deixis-voice.com/sdk.js" data-key="pk_live_…" async></script>
<textarea id="question"></textarea>
<deixis-mic for="question"></deixis-mic>
That is a whole mic button. On every press it decides what to do:
- In a browser where Deixis has answered before, it records on the user's computer: press to start, press again to stop. While it records, the line beside the mic says "On this computer · Deixis"; afterwards a laptop mark keeps those words as its tooltip.
- Everyone else, with your key, records in the browser and is transcribed in the cloud. A small red cloud beside the mic marks every such take; press it for a short explanation and the offer of Deixis. If Deixis has answered before but is not running now, that take goes through the cloud and the mark says so.
- Without a key, or once your cloud minutes are used up, a user without Deixis gets a short offer to get it, with a download link that carries your site, and an "I already have it" for people who installed it some other way.
The words land in the field for names, a textarea, an input or a contenteditable: at the
caret, replacing any selection, followed by an input event (at the end of a field the user has not
been in). They go in through the field's own value setter, so a React controlled input sees the
change. The element changes no word; at most it adds a single space where they meet your text.
What it handles so you do not have to:
- No request without a reason. Loading the script and rendering the button send nothing. The element reaches 127.0.0.1 only from a press, once Deixis has answered in this browser or the user says they have it, so nobody with nothing installed sees the browser's local-network question.
- The microphone tick. If the user has not let your site start the microphone, the element names the one tick in Deixis's settings and offers hold-to-talk behind its own button.
- Everything else that can go wrong: Deixis not running, Deixis still getting its speech model after an install, the browser blocking your site or the microphone, a version of Deixis too old to start the microphone, a take that ran to its limit. Each gets its own short message.
- Phones, tablets, Linux and ChromeOS. Deixis on a phone does not take dictation for web pages, and there is no Deixis for Linux or ChromeOS. With your key, those get the cloud route; without one, the element renders nothing.
Three events tell your code what happened. All of them bubble out of the element:
document.addEventListener('deixis-transcript', (e) => save(e.detail.text));
// deixis-transcript { text, route } route is 'local' or 'cloud'
// deixis-state { state, route }, on every change
// deixis-error { reason }: not_granted, not_ready, blocked, not_running, no_credit, busy, …
Call preventDefault() on deixis-transcript to put the words in yourself, for an editor that keeps
its own model of the text.
Styling. The button lives in a shadow root, so your stylesheet cannot break it by accident. Five
custom properties reach in: --deixis-accent, --deixis-radius, --deixis-font, --deixis-line
and --deixis-text. ::part(button) covers the rest, and data-state and data-route on the
element let you style one state. Left alone, it wears your page's font and text colour. The cloud
line can be restyled through those properties but not hidden: it has no part, and the element
overrules the stylesheet tricks that would hide it. Keeping it visible is a condition of the key.
The attributes. On the script tag: data-key, your publishable key, which turns the cloud route
on; data-terms, up to 36 comma-separated words the cloud should expect (product names, people,
jargon); data-partner, your slug, which download links carry (with a key it is optional: they
carry your site, one of your key's); data-name, the name the element's sentences use for your site
(your page title by default); and data-simulate. On the element: for; label for the button's accessible name, "Dictate" by
default; disabled, which stops a press from starting a take (while your assistant is still
replying, say) but never stops a take already running from being stopped; and line. The line
beside the mic goes on the side that keeps the button still, measured from your layout: before it at
the end of a row (after a one-line field, say), after it elsewhere. line="start" or line="end"
decides it instead, and right-to-left pages are mirrored.
Loading it. In the head, or when the component with the mic first mounts, so a page whose
visitors never dictate loads nothing at all. It upgrades any <deixis-mic> already in the page;
until then the element draws nothing.
Testing without Deixis. data-simulate plays one scenario with canned words, with no Deixis, no
microphone and no request. Leave the value empty for the ordinary path, or name one: offer,
mac, not_granted, blocked, asking, outdated, not_running, not_ready, no_model, busy, expired, failed and phone, or the cloud route's
cloud, cloud_miss, cloud_failed, no_credit, cap_reached and phone_cloud. The simulated
words are always "This is Deixis in simulate mode. No microphone was used.", and a simulated mic
renders on a Linux test machine too, in a browser or in jsdom.
A Content Security Policy needs script-src https://deixis-voice.com https://challenges.cloudflare.com, frame-src https://challenges.cloudflare.com (the cloud route's
Turnstile check, which runs unseen unless Cloudflare wants a click), and connect-src http://127.0.0.1:47831 http://127.0.0.1:47832 http://127.0.0.1:47833 https://api.deixis-voice.com.
In current browsers the element's styles come from a stylesheet built by the script, so style-src
needs nothing added. Safari before 16.4 cannot build one and falls back to a <style> element,
which a style-src without 'unsafe-inline' blocks: there the button works but is unstyled.
The file is served minified. Every rule in it has its reason written beside it in the commented source, which is the same code.
About ten lines
If you want your own button rather than ours, the element is built on a handful of calls you can use directly. They talk only to Deixis on the user's computer.
Load the SDK and ask. available() tells you whether there is a Deixis on this machine willing to
talk to your origin, and dictate() asks the user for one dictation.
<script src="https://deixis-voice.com/sdk.js"></script>
button.addEventListener('click', async () => {
const { installed, download } = await deixis.available();
if (!installed) return showDownloadLink(download); // a download that knows your site
// The user holds their Deixis key and speaks; the words come back cleaned.
input.value = await deixis.dictate();
});
That is the whole integration for the common case. For these calls there is no API key, no account, no npm dependency, no build step and no server component on your side.
If you want the microphone button most apps actually want — press to talk, release to stop, with no keyboard chord for the user to learn — there is a second pair of calls, and the user grants that separately:
await deixis.start({ onPartial: (text) => (preview.textContent = text) });
// …the user speaks, your button says Stop…
input.value = await deixis.stop(); // the finished, cleaned transcript
While that runs, Deixis shows its own overlay naming your site, with its own Stop, and ends the recording if your page goes away or after ten minutes. That is deliberate: a microphone opened by a web page should always be visibly one, and closable by the person it is pointed at.
Three rules the design puts on you
Each exists because the alternative would be a way to abuse somebody's microphone. The drop-in mic keeps all three for you; build your own button and they are yours to keep.
1. Call it from a real user action, never on page load. Chrome gates a page's first request to a loopback address behind a Local Network Access prompt, and while it is unanswered the request neither succeeds nor fails: at load time, a hung page with nothing in the console. From a click it is a one-time question, and after the user allows it a probe costs about two milliseconds.
2. installed: false means "could not reach it", not "not installed". Deixis may be running
with the door off, your origin may not be on the user's list, or they may not have answered the
browser yet, and a page that is not allowed to talk to Deixis is told nothing about whether it is
there. Treat it as "no voice right now". The one thing you can tell apart is the browser's own
refusal, permission: 'denied', which no retrying fixes until the user unblocks your site.
3. You are never given the microphone, only the words. dictate() does not open anything: it
asks Deixis to route the user's next hold-to-talk to you, and if they never speak, your promise
rejects on its deadline. Your page sees neither the audio nor anything else the user keeps in
Deixis.
Design for the missing grant, too. "Start and stop the microphone" is off for every site until the
user ticks it, or leaves it ticked on the first-run card of a site on Deixis's own list of partners,
so a start() without it rejects with not_granted — offer the button, and fall back to
dictate() with a line telling the user to hold their key. A fresh install's start() can also
reject with not_ready while Deixis downloads its speech model: the error's model is
downloading while that runs, and missing when the user has to open Deixis to start it.
When Deixis is not on the machine
This is where most local-companion integrations quietly fail: the user installs it, presses your button, and nothing happens, because the app has no idea your site exists.
So do not write the download link yourself. available() hands you one:
const { installed, download } = await deixis.available();
if (!installed) link.href = download; // carries your site's name
An installer fetched through that link arrives knowing where it came from. On its first run Deixis puts one card on screen with your site's name on it — Allow or Not now — and Allow does the four settings steps at once: the door on, your origin listed, the permissions decided under your name. If the speech model is not on the computer yet, the card says so, with its size, and Allow downloads it too.
Note what the card is: a request, answered by the person. A filename is chosen by whoever serves the file, so an installer that granted on the strength of one would let any page allowlist itself, and open a microphone. So the microphone tick starts unticked for an ordinary site, and "Not now" is nothing at all. On the card of a site on Deixis's own list of partners it starts ticked, and the user can untick it.
A page on plain http, on localhost or on a non-standard port gets the plain download link,
because the installer only carries a site it could safely offer. The web door arrived with Deixis
1.1.12; on an earlier version available() reports that nothing answered.
If your product is not a web app
A desktop program connects to the same engine through a named pipe on Windows or a unix socket
on macOS, never a TCP port, using an address and a key Deixis writes beside the user's settings
while the door is open. Five requests are all it may send, each a tick the user controls: a short
question on the HUD, a letter on the mode palette, a dictation the user routes to it, a click the
user makes on screen, and a line typed into a field. The last two are off for every program until
the user switches them on. core/examples/client.rs drives all five, and
the local connections docs have the whole model.
A server does not connect to Deixis at all: Deixis pushes to it. Point a webhook at your URL and every finished note, grab or translation arrives as one HMAC-signed JSON POST; the webhook docs verify one in Node.
Just dictating into your own tools? Deixis already types into Claude Code, Cursor, VS Code and Windows Terminal.
What it costs, for you and for them
On the user's computer, nothing, on both sides. The SDK is a static file, and dictation in Deixis is free forever with no account, so "install Deixis" is not a purchase you ask your users to make. What people pay us for is the optional cloud tier (cleanup, translation, meeting notes) at $49 a year, and nothing on this page needs it.
The cloud route is the part that costs, and you pay for it, not your users: minutes prepaid against your key, starting with 10,000 free ones, good for a year. When they run out the cloud route pauses, and the mic offers Deixis on a computer and stands down where Deixis cannot run, for up to an hour after you top up. Your users never see a balance, and every user who moves to Deixis stops costing you cloud minutes, whether or not they ever pay us. The partner programme has the prices in one place. Partners are set up by us, keys included, on these terms: write to support@deixis-voice.com with your site's address.
What it will not do
- It is not a speech API. There is no endpoint you can call from your backend, and no way to transcribe a file your server holds. The cloud route answers only the element, on your own site's pages, behind your key and a Turnstile check, with the user present and told.
- Seven languages. Deixis dictates in the one its user set (which).
- Windows needs AVX2 (2013 or later); macOS needs 13 or later on Apple silicon. There is no Linux build; on Linux the drop-in mic uses the cloud route or draws nothing.
- You cannot pre-allow yourself, silently enable the door, or read anything the user has not handed you in the moment. Every one of those is refused rather than rate-limited.
Before you ask
Questions people search for
Does any audio reach my servers or yours?
Your servers, never. Ours, only on the cloud route, for a user whose Deixis has not connected to your site, is not running, or who has none: their recording passes through our server to Cloudflare's speech model and the text comes back. We keep neither the recording nor the words, Cloudflare does not train on them, and the user is told on every take. With Deixis running and connected to your site, recognition happens on the computer and nobody receives the recording.
Do I need an API key or an account?
For the cloud route, a publishable key, which we issue; it sits in your page and names your sites. For the local route and the low-level calls, no: the door is on the user's machine, and there is no registration step for you or for them.
What happens if the user does not have Deixis?
With a key, the drop-in mic transcribes in the cloud and says so, with the offer of Deixis behind
the line. Without one, it offers Deixis. available() returns installed: false along with a
download link that carries your site's name, so the copy they install can offer them your site on
first run with a single Allow.
Can my page turn on the user's microphone?
On the user's computer, only if they have ticked "Start and stop the microphone" for your origin,
which is off by default except on a partner's first-run card. Without it, start() is refused and
you fall back to dictate(), which needs the user to hold their own key and speak. On the cloud
route the browser asks the user itself, as for any site.
Can I use this in a desktop app rather than a web page?
Yes — a local pipe on Windows or a unix socket on macOS, with five requests the user grants individually, and a worked example in the repository. See local connections.
Do partners earn commission?
Yes: 20%, for life, of every Pro or Team payment after tax and payment-processing fees, from users who first pay within three months of arriving through you. Cloud credit or cash, monthly from $50: see the partner terms.
Keep reading
Related pages
Best dictation software for Windows
Fifteen Windows dictation tools compared, every fact dated from the maker's own pages — including what our own tool cannot do. Read the disclosure.
Offline dictation on Windows
Dictation that works with no internet: speech recognition on your own device, free, no account. Which Windows speech-to-text tools genuinely run offline.
Free voice to text on Windows that types where you are
Free dictation for Windows that types into any app: hold a key, speak, and punctuated text lands at your cursor. Recognition runs on your own processor.
The first five minutes, from the installer to your first words
From the Deixis installer to your first dictated sentence in another app, then one more thing worth trying. Windows and Mac, with no account.
Voice typing for your whole team, on one invoice
What a Deixis seat buys a software team, what stays free without one, the price, and how to bring a whole team on in an afternoon.
What you are downloading
This is Deixis, a desktop app for Windows.
The Download button hands you a signed Windows installer, Deixis_<version>_x64-setup.exe, published by Dappit — Windows names the publisher before it runs. There is no bundled extra software and no toolbar. Deixis needs no account to install, and none of what it does on your own PC is behind a sign-up. What it runs on.
It installs for your account alone, with no administrator prompt, and starts with Windows until you switch that off in Settings → Startup. On a PC without Microsoft’s WebView2 runtime, which Windows 11 already has, the installer fetches it from Microsoft. How to uninstall it · The licence · Privacy policy · Terms of service · support@deixis-voice.com
Hold a key. Speak. Keep working.
Deixis is free, needs no account, and runs on your own device. Everything on this page is in the current release.
v1.3.2 · 64‑bit Windows 10/11 on Intel or AMD · macOS 13 on Apple silicon · 51 MB · nothing else to install · also for Windows · Android on Google Play
Everything on this page about Deixis is from its documentation for the current release. Something out of date? Tell us.