npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vidtreo/recorder-vue

v1.6.7

Published

Vue 3 components and composables for @vidtreo/recorder - video recording SDK

Readme

@vidtreo/recorder-vue

Vue 3 components and composables for the Vidtreo video recording SDK. Drop the recorder into any Vue app with a single tag, or build a fully custom UI on top of the same battle-tested composables that power @vidtreo/recorder-react — same recording pipeline, same upload queue, same i18n, native Composition API ergonomics.

What you get out of the box

  • 🎥 Camera + screen capture with one-click source switching, mute, pause/resume, and device selection.
  • ⏱️ Countdown, timer, audio meter, transcoding progress, upload progress — all wired and styled.
  • 🔐 Permission flow with a polished overlay that walks the user through allowing camera + mic, plus a recovery guide when they were denied.
  • 📱 Mobile-aware — overlay modal, embedded mode, or the device's native camera (file input), selectable via the mobileMode prop.
  • 🌐 i18n out of the box (English + Spanish) and full per-string overrides for any language you want.
  • 🧪 SSR-safe — every browser API is gated to client-side mount. Drop it in Nuxt with @vidtreo/recorder-nuxt and forget about hydration mismatches.
  • 🛠️ Composable API for building your own UI — same shape as @vidtreo/recorder-react, so React-to-Vue migrations are 1:1.

Installation

npm install @vidtreo/recorder-vue @vidtreo/recorder

Peer dependencies:

  • @vidtreo/recorder >=1.6.0
  • vue >=3.0.0

Don't forget the stylesheet — either import it once in your entry, or rely on the built-in CSS injection (added to <head> automatically when the package loads).

// Optional explicit import — useful if you bundle styles separately
import "@vidtreo/recorder-vue/styles.css";

Quick start

Drop-in component (2 lines)

<script setup lang="ts">
import { VidtreoRecorder } from "@vidtreo/recorder-vue";
</script>

<template>
  <VidtreoRecorder :recorder-props="{ apiKey: 'your-api-key' }" />
</template>

Using environment variables

For Vite-based apps, expose the key via import.meta.env:

# .env
VITE_VIDTREO_API_KEY=your-api-key
<script setup lang="ts">
import { VidtreoRecorder } from "@vidtreo/recorder-vue";

const apiKey = import.meta.env.VITE_VIDTREO_API_KEY as string;
</script>

<template>
  <VidtreoRecorder :recorder-props="{ apiKey }" />
</template>

Component API

The component accepts a single recorder-props object so the discriminated union (demo: true vs apiKey) stays type-safe at the call site. Events use the standard Vue @event-name listener syntax.

Props (recorder-props)

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | apiKey | string | Yes* | – | API key for authentication. *Optional when demo: true. | | demo | boolean | No | false | Demo mode. Skips upload and lets you download the local recording. | | backendUrl | string | No | https://core.vidtreo.com | Backend API URL. | | countdownDuration | number | No | – | Pre-recording countdown (milliseconds). | | minTimeRecord | number | No | – | Minimum recording time in ms before Stop is allowed (e.g., 10_000). | | maxRecordingTime | number | No | – | Maximum recording time in milliseconds. | | userMetadata | Record<string, unknown> | No | – | Custom metadata attached to uploads. | | enableSourceSwitching | boolean | No | true | Toggle between camera and screen. | | enableMute | boolean | No | true | Show the mute/unmute button. | | enablePause | boolean | No | true | Show pause/resume buttons. | | enableDeviceChange | boolean | No | true | Show the settings panel with cam/mic selectors. | | enableTabVisibilityOverlay | boolean | No | false | Show overlay when the user switches tabs (camera recordings only). | | tabVisibilityOverlayText | string | No | localized default | Custom message for the tab-visibility overlay. | | mobileMode | "embed" \| "overlay" \| "native" | No | "overlay" | Mobile experience. "embed" = same as desktop, "overlay" = fullscreen modal, "native" = device's native camera (file input). | | nativeCamera | boolean | No | – | Deprecated — use mobileMode: "native" instead. | | maxFileSize | number | No | – | Maximum file size in MB (native camera mode). | | lang | string | No | "en" | Language code ("en" or "es"). | | texts | PartialTranslations | No | – | Per-key text overrides. |

Events

| Event | Payload | Fired when | |-------|---------|------------| | recording-start | – | Recording begins (after the countdown finishes). | | recording-stop | – | Recording ends and processing starts. | | upload-progress | progress: number (0..1) | Each chunk is uploaded. | | upload-complete | { recordingId: string; uploadUrl: string } | Upload finishes. | | upload-error | error: Error | Upload fails. | | transcoding-progress | progress: number (0..1) | Native-camera transcoding progress. | | error | error: Error | Any unhandled error. |

Example with listeners

<script setup lang="ts">
import { VidtreoRecorder } from "@vidtreo/recorder-vue";
import type { VidtreoRecorderProps } from "@vidtreo/recorder-vue";

const recorderProps: VidtreoRecorderProps = {
  apiKey: "your-api-key",
  countdownDuration: 3,
  minTimeRecord: 10_000,
  lang: "en",
};

function onComplete(result: { recordingId: string; uploadUrl: string }) {
  console.log("Recording uploaded:", result.recordingId);
  console.log("View at:", result.uploadUrl);
}

function onProgress(progress: number) {
  console.log(`Upload: ${Math.round(progress * 100)}%`);
}

function onError(error: Error) {
  console.error("Recorder error:", error.message);
}
</script>

<template>
  <VidtreoRecorder
    :recorder-props="recorderProps"
    @upload-complete="onComplete"
    @upload-progress="onProgress"
    @error="onError"
  />
</template>

Composable API

When the default component doesn't fit your UI, drop down to the useVidtreoRecorder composable and assemble your own.

<script setup lang="ts">
import { useVidtreoRecorder } from "@vidtreo/recorder-vue";

const { state, actions, audioLevel, controller } = useVidtreoRecorder({
  apiKey: "your-api-key",
  onUploadComplete: (result) => console.log("Upload complete:", result),
});
</script>

<template>
  <div>
    <video v-if="state.stream" :srcObject="state.stream" autoplay muted playsinline />

    <button v-if="state.recordingState === 'idle'" @click="actions.startRecording()">
      Start
    </button>
    <button v-else @click="actions.stopRecording()">
      Stop
    </button>

    <div>Timer: {{ state.timer }}</div>
    <div>Audio level: {{ audioLevel }}</div>
    <div v-if="state.error" class="error">{{ state.error }}</div>
  </div>
</template>

What the composable returns

{
  state: Reactive<VidtreoRecorderState>;      // mutate freely, fully reactive
  actions: VidtreoRecorderActions;            // plain methods
  audioLevel: Ref<number>;                    // 0..1 — perfect for waveform UIs
  controller: ShallowRef<RecorderController>; // raw core SDK if you need it
}

state

{
  recordingState: "idle" | "countdown" | "recording";
  stream: MediaStream | null;
  isMuted: boolean;
  isPaused: boolean;
  isAudioReady: boolean;
  hasAudioFailed: boolean;
  error: string | null;
  errorCode: string | null;
  countdown: number | null;
  timer: string;                  // "00:12" format
  uploadProgress: number | null;  // 0..1 or null
  transitionMessage: string | null;
  isInitialized: boolean;
  recordedBlob: Blob | null;      // populated in demo mode
  audioWarning: AudioWarning | null;
  audioRecovered: boolean;
  devices: {
    cameras: MediaDeviceInfo[];
    microphones: MediaDeviceInfo[];
    selectedCamera: string | null;
    selectedMic: string | null;
  };
}

actions

| Action | Signature | What it does | |--------|-----------|--------------| | startRecording | (sourceType?: "camera" \| "screen") => Promise<void> | Begin recording (after countdown if configured). | | stopRecording | () => Promise<RecordingStopResult> | Stop and trigger upload. | | pauseRecording | () => void | Pause an active recording. | | resumeRecording | () => void | Resume from pause. | | toggleMute | () => void | Toggle the audio mute state. | | switchSource | (sourceType: "camera" \| "screen") => Promise<void> | Swap between camera and screen during preview/recording. | | changeCamera | (deviceId: string) => Promise<void> | Switch to a different camera. | | changeMic | (deviceId: string) => Promise<void> | Switch to a different microphone. | | startPreview | (sourceType?: "camera" \| "screen") => Promise<void> | Open the stream without recording. | | stopPreview | () => void | Tear the preview stream down. | | downloadVideo | () => void | Download the last recordedBlob (demo mode). | | cleanup | () => void | Release all resources. Useful before unmounting. |

Specialized composables

| Composable | Purpose | |------------|---------| | useMobileWebRecorder(config) | Wraps useVidtreoRecorder and adds isModalOpen, openModal, closeModal, canCloseModal for the mobile overlay experience. | | useNativeCamera(config) | File-input + transcoding flow used when mobileMode: "native". Returns { state, actions } with handleFileSelect, processAndUpload, downloadVideo, reset. | | usePermissionFlow(options) | Drives the camera/mic permission overlay. Returns { isActive, isComplete, currentStep, steps, recoveryData, requestPermission, retryPermission } — useful if you want to build a fully custom permission UI. | | useRecorderTranslations(translations) | Splits a TranslationKeys object into preview, buttons, and settings subsets as ComputedRefs. Accepts MaybeRefOrGetter<TranslationKeys> so it stays reactive when the language changes. |

Internationalization

Built-in: English (en) and Spanish (es). Use the lang prop to switch, and texts to override individual strings or to ship a brand-new language entirely.

Switch language

<template>
  <VidtreoRecorder :recorder-props="{ apiKey, lang: 'es' }" />
</template>

Override individual strings

<script setup lang="ts">
import { VidtreoRecorder } from "@vidtreo/recorder-vue";

const recorderProps = {
  apiKey: "your-api-key",
  lang: "en",
  texts: {
    record: "🔴 Start Capture",
    stop: "⏹️ End Capture",
    settings: "Options",
  },
};
</script>

<template>
  <VidtreoRecorder :recorder-props="recorderProps" />
</template>

Ship a completely custom language (e.g., French)

<script setup lang="ts">
import { VidtreoRecorder } from "@vidtreo/recorder-vue";
import type { PartialTranslations } from "@vidtreo/recorder-vue";

const french: PartialTranslations = {
  initializingCamera: "Initialisation de la caméra...",
  grantPermissions: "Accordez les autorisations de caméra et de microphone",
  switchingDevice: "Changement d'appareil...",
  recordingStartsIn: "L'enregistrement commence dans...",
  switchingSource: "Changement de source...",
  rec: "ENREG",
  settings: "Paramètres",
  record: "Enregistrer",
  stop: "Arrêter",
  pause: "Pause",
  resume: "Reprendre",
  mute: "Muet",
  unmute: "Activer le son",
  switchSource: "Changer de source",
  camera: "Caméra",
  microphone: "Microphone",
  uploading: "Téléchargement...",
};
</script>

<template>
  <VidtreoRecorder
    :recorder-props="{ apiKey: 'your-api-key', lang: 'fr', texts: french }"
  />
</template>

Dynamic language switching

The component is fully reactive — change lang and the UI re-localizes without a remount:

<script setup lang="ts">
import { ref } from "vue";
import { VidtreoRecorder } from "@vidtreo/recorder-vue";

const language = ref<"en" | "es">("en");
</script>

<template>
  <select v-model="language">
    <option value="en">English</option>
    <option value="es">Español</option>
  </select>

  <VidtreoRecorder :recorder-props="{ apiKey: 'your-api-key', lang: language }" />
</template>

Translation keys

| Key | English | Spanish | |-----|---------|---------| | initializingCamera | Initializing camera... | Inicializando cámara... | | grantPermissions | Grant camera and microphone permissions when prompted | Otorga permisos de cámara y micrófono cuando se solicite | | switchingDevice | Switching device... | Cambiando dispositivo... | | recordingStartsIn | Recording starts in... | La grabación comienza en... | | switchingSource | Switching source... | Cambiando fuente... | | rec | REC | GRAB | | settings | Settings | Configuración | | record | Record | Grabar | | stop | Stop | Detener | | minimumRecordingTimeNotReached | You have not met the minimum recording time yet | Aun no cumples el tiempo minimo de grabacion | | pause | Pause | Pausar | | resume | Resume | Reanudar | | mute | Mute | Silenciar | | unmute | Unmute | Activar sonido | | switchSource | Switch Source | Cambiar Fuente | | camera | Camera | Cámara | | microphone | Microphone | Micrófono | | uploading | Uploading... | Subiendo... |

The full key list lives in src/i18n/translations.ts — there's a key for every visible string, including the permission flow recovery guide.

Mobile experience

mobileMode controls how the recorder behaves on mobile devices:

| Value | Behavior | |-------|----------| | "overlay" (default) | A landing screen with "Allow Access". On tap, a fullscreen modal opens (via <Teleport>) with the same UI as desktop. | | "embed" | The recorder embeds inline, identical to desktop. | | "native" | Skips the SDK UI entirely and opens the device's native camera via a file input. Useful when WebCodecs isn't reliable on the user's browser. |

The <VidtreoRecorder> component probes browser capabilities on mobile and falls back gracefully when WebCodecs isn't available.

SSR (Nuxt, Astro-Vue, etc.)

Every browser API is gated to onMounted/if (typeof window !== "undefined"). If you're on Nuxt 3, the cleanest path is the @vidtreo/recorder-nuxt module — it registers the component as client-only and injects the CSS for you.

For other SSR setups, wrap the component in <ClientOnly> (Nuxt) or guard it behind a mount check in your framework's equivalent.

TypeScript

Every public surface is typed. Import types directly:

import type {
  VidtreoRecorderProps,
  VidtreoRecorderState,
  VidtreoRecorderActions,
  UseVidtreoRecorderConfig,
  UseVidtreoRecorderReturn,
  PartialTranslations,
  TranslationKeys,
  MobileMode,
  AudioWarning,
  RecordingStopResult,
} from "@vidtreo/recorder-vue";

Package structure

| What | Where | |------|-------| | Top-level component | src/components/VidtreoRecorder.vue | | Desktop / embed UI | src/components/StandardRecorder.vue | | Mobile overlay | src/components/MobileWebRecorderUI.vue | | Native camera | src/components/NativeCameraUI.vue | | Composables | src/composables/ | | UI primitives | src/components/ui/ | | i18n data | src/i18n/translations.ts | | Framework-agnostic helpers | src/utils/, src/services/ |

The recording engine, transcoding worker, and upload pipeline live in @vidtreo/recorder.

License

MIT