This page is for anyone shipping a web app (plain JS, React, or Next.js) with Livqeno calls. It covers what a browser needs, how to check for it in your app, and which browsers have been tested.
Why it matters. Your users open your app in whatever browser they have: an old work laptop, an in-app browser inside a social app, an iPhone. If a call can't work there, it's much better to tell them up front ("please open this in Chrome") than to show a call screen that silently stays black.
Chat needs only WebSocket, which every current browser has. The checks
below are mostly about calls.
What a call needs
Three browser features:
| Feature | Used for |
|---|---|
RTCPeerConnection | The media connection |
navigator.mediaDevices.getUserMedia | Camera and microphone |
WebSocket | Signaling and chat |
Check before you show the call
Run this in your browser app before you render the call screen, for example when the user lands on the "Join call" page:
import { getBrowserSupportDetails, isBrowserSupported } from '@livqeno/rtc';
if (!isBrowserSupported()) {
showUnsupportedNotice();
}
const { supported, missing } = getBrowserSupportDetails();
// missing: ['RTCPeerConnection'] — name the thing that is absentmissing lists each missing feature. Use it to tell the user exactly what's
wrong, instead of just "your browser is unsupported".
Optional features: check them yourself
Some features work only in some browsers. A call still works without them,
so getBrowserSupportDetails() only checks the three features above. Check
optional ones yourself, so you can hide buttons that would never work (for
example, no "Share screen" button on a phone):
| Feature | How to check | Missing on |
|---|---|---|
| Screen sharing | typeof navigator.mediaDevices?.getDisplayMedia === 'function' | Mobile browsers |
| Speaker selection | 'setSinkId' in HTMLMediaElement.prototype | Safari |
If you call something the browser can't do, it usually throws
NOT_SUPPORTED. One exception: speaker selection on Safari throws
DEVICE_NOT_FOUND (see quirks below).
| Error | Meaning | What to do |
|---|---|---|
NOT_SUPPORTED | This device can never do this. | Hide the button. |
MEDIA_ERROR | Something went wrong this time. | Retry. |
Which browsers are tested
Support is feature-detected. An untested browser still reports as "supported" because the features exist. That doesn't prove the whole call works.
| Browser | Feature check | Tested with real media |
|---|---|---|
| Chrome / Edge (Chromium) | Passes | Yes |
| Firefox | Passes | No |
| Safari (macOS) | Passes | No |
| Safari (iOS) | Passes | No |
If you have a broad audience, test on the browsers your users use. For example, if many of your users are on iPhones, test a full call in iOS Safari before launch. This is also listed in Known limitations.
Browser quirks to know
These come from the browsers, not from Livqeno:
- iOS Safari needs
playsInline.track.attach()sets it for you. That's whyattach()gives you an element instead of asking for one. - Autoplay needs a click. Remote audio may not play until the user interacts with the page. Put "Join" behind a button.
- Safari has no
setSinkId.setSpeakerDevice()throwsDEVICE_NOT_FOUNDthere. - Mobile browsers can't share the screen. Check first and hide the button.
- Device names are blank before permission. List devices again after
getUserMediasucceeds, or your picker shows empty names.
Server-side rendering
@livqeno/rtc, @livqeno/chat, and every @livqeno/react hook run
only in the browser. In Next.js, mark the component:
'use client';<LivqenoRoom> and all hooks must run in the browser. See
Next.js.
Next steps
- RTC troubleshooting: what to do when a call works in one browser but not another.
- Permissions: handling camera and mic prompts in the browser.
- Known limitations: everything else that isn't supported yet.