V
Vibeview
Pricing

VibeView SDK

The VibeView SDK lets you embed live iOS and Android simulators directly into your website, documentation, or web application. Users can interact with a real device stream right in the browser.

Overview

The SDK handles the full lifecycle of a simulator session: creating it, connecting to the video stream, capturing user interactions, and cleaning up resources when done. It supports two usage patterns:

  • React component — A <VibeView /> wrapper for React applications (available via the @vibeview/sdk/react subpath).
  • Vanilla JS client — The VibeViewClient class for any JavaScript environment.

Both approaches use the same underlying client and support the same configuration options.

Installation

Install the SDK from npm:

npm install @vibeview/sdk

Or with Yarn:

yarn add @vibeview/sdk

The SDK requires Node.js 14+ and works in modern browsers with WebCodecs or Media Source Extensions support (Chrome 94+, Edge 94+, Safari 16.4+).

React Usage

Import the component from the @vibeview/sdk/react subpath:

import { VibeView } from '@vibeview/sdk/react';

function SimulatorDemo() {
  return (
    <VibeView
      deviceType="ios"
      token="your-auth-token"
      autoStart={true}
      style={{ width: 375, height: 812 }}
    />
  );
}

React is an optional peer dependency. The SDK works without React installed — the core @vibeview/sdk import has no React dependency.

Vanilla JS Usage

Use the VibeViewClient class directly when working outside React:

import { VibeViewClient } from '@vibeview/sdk';

const client = new VibeViewClient('#simulator-container', {
  apiUrl: 'https://vibeview.io',
  deviceType: 'ios',
  token: 'your-auth-token',
  autoStart: true,
});

await client.ready();

client.on('session:started', (session) => {
  console.log('Session started:', session.sessionId);
});

The first argument is a CSS selector string or an HTMLElement reference where the simulator will be rendered.

There is also a convenience helper that creates the client and waits for it to be ready in one call:

import { vibeview } from '@vibeview/sdk';

const client = await vibeview('#container', {
  deviceType: 'android',
  autoStart: true,
});

Configuration

Pass a configuration object when creating a client. All properties are optional.

PropertyTypeDefaultDescription
apiUrlstringhttps://vibeview.ioBackend API URL.
wsUrlstringwss://vibeview.ioWebSocket URL for streaming.
tokenstringBearer token for authentication.
sessionIdstringConnect to an existing session instead of creating a new one.
deviceType'ios' | 'android' | 'roku'Device platform to launch. For TV, combine with deviceCategory: 'tv' (Apple TV = 'ios' + 'tv'; Android TV = 'android' + 'tv'). 'roku' streams a Roku device (beta).
deviceCategory'phone' | 'tablet' | 'tv'omitted = any handheldDevice form factor. Omit to allocate any handheld (any phone or tablet); pass 'tv' for Apple TV / Android TV sessions, or 'phone'/'tablet' to narrow.
deviceIdstringRequest a specific device by ID.
autoStartbooleanfalseStart the session immediately on initialization.
scalenumber | 'auto''auto'Device scale factor (10—100), or 'auto' to fit the container.
screenOnlybooleanfalseShow only the screen without device chrome.
deviceColor'black' | 'white''black'Device chrome color.
orientation'portrait' | 'landscape''portrait'Initial device orientation.
displayRotation0 | 90 | 180 | 2700Visual rotation (degrees clockwise) the host applies to the canvas. The SDK inverse-transforms taps so they still land on the correct device pixels. Useful when displaying a landscape-locked app upright inside a portrait canvas.
readOnlybooleanfalseDisable user interactions (view-only mode).
decoder'webcodecs' | 'mse''webcodecs'Video decoder. WebCodecs has lower latency; MSE is more broadly compatible.
enableAdaptiveQualitybooleantrueAutomatically adjust bitrate/FPS quality tiers to match network conditions.
enableHEVCbooleantrueNegotiate HEVC (H.265) when the browser supports it; falls back to H.264 otherwise.
debugbooleanfalseEnable debug logging.
classNamestringCustom CSS class for the container element.
stylePartial<CSSStyleDeclaration>Inline styles for the container element.

Canvas Options

The canvas property accepts an object for fine-tuning rendering:

PropertyTypeDefaultDescription
acceleratedbooleantrueUse hardware acceleration.
imageSmoothingEnabledbooleantrueEnable image smoothing when scaling.

Events

The client emits events you can listen to with client.on():

client.on('session:status', (status) => { /* pending, starting, active, stopped, failed */ });
client.on('session:started', (session) => { /* session info with sessionId, deviceType, etc. */ });
client.on('session:failed', (error) => { /* Error object */ });
client.on('session:ended', () => { /* session stopped */ });
client.on('stream:started', () => { /* video frames arriving */ });
client.on('stream:stopped', () => { /* video stream ended */ });
client.on('stream:frame', (frameCount) => { /* a video frame was received (for custom rendering) */ });
client.on('stream:dimensions', ({ width, height }) => { /* video dimensions changed, e.g. after rotation */ });
client.on('connection:state', (state) => { /* connecting, connected, disconnected, reconnecting, error */ });
client.on('connection:failed', () => { /* reconnection gave up after all retry attempts */ });
client.on('error', (error) => { /* general error */ });
client.on('interaction', (action) => { /* user tap, swipe, etc. */ });
client.on('interaction:enhanced', (action) => { /* recorded action enriched with element context */ });
client.on('device:orientation', (orientation) => {
  /* 'portrait' | 'portrait_upside_down' | 'landscape_left' | 'landscape_right' — iOS only */
});

Device Control

The client exposes programmatic device control alongside direct user interaction. All methods require an active session.

await client.tap(160, 320);
await client.swipe(160, 600, 160, 200, 300);
await client.typeText('hello@example.com');
MethodDescription
tap(x, y)Tap at coordinates (pixels in the streamed video).
swipe(x1, y1, x2, y2, duration?)Swipe from one point to another; duration in milliseconds (default 500).
typeText(text)Type a full string as a single command.
type(text)Legacy variant: sends the string character by character.
pressKey(keycode)Press a hardware key (Android/TV), e.g. 'BACK', 'HOME', 'DPAD_UP', 'DPAD_CENTER'.
pressButton(button)Press an iOS hardware button, e.g. 'HOME', 'LOCK'.
rotate(degrees?)Rotate the device; 90, 180, or 270 (default 90).
setLocation(lat, lon)Set the simulated GPS location.
setAppearance(mode)Switch the device between 'light' and 'dark' appearance.
screenshot(options?)Capture the current frame; returns a data-URL string. Options: format ('png' default, 'jpeg', 'webp') and quality (0–1, default 0.92).
installApp(options)Install an app into the session. Pass file (a File/Blob) or url (downloaded first), plus optional launchAfterInstall (default false).

TV devices

On TV sessions (Apple TV / Android TV), interaction is focus-based — the platform walks the d-pad focus to the target element instead of tapping coordinates:

MethodDescription
tapFocusedTv(locator)Move d-pad focus to the element matching the locator and press SELECT to activate it.
focusElementTv(locator)Move d-pad focus to the element without activating it.

Both take a locator object with any of accessibilityId, resourceId, text, and rect ({ x, y, width, height }). Both are fire-and-forget: they resolve when the command is sent, not when the walk completes.

Live keyboard

For live typing from a physical keyboard (as opposed to programmatic typeText), the client provides buffer-aware keystroke methods. Keystrokes are injected to the device immediately; while recording, consecutive characters are aggregated into a single type_text action instead of one action per keypress:

MethodDescription
liveType(char)Inject a single printable character. While recording, it accumulates in a pending buffer and fires a recording:buffer event so UIs can show in-flight text.
liveKey(keycode)Inject 'RETURN' or 'BACKSPACE'. RETURN flushes the pending buffer as one type_text action, then records a discrete key press; BACKSPACE pops the last pending character (or records a discrete key press if the buffer is empty).
flushKeyboardBuffer()Commit any pending buffered text as a single aggregated type_text action. Idempotent — an empty buffer is a no-op. Called automatically when another action interrupts typing and when recording stops.

Enhanced Recording

Enhanced recording captures user interactions together with the UI element under each interaction (accessibility ID, text, bounds). The resulting action list is what powers Generate AI Test — upload it to have the AI turn a manual session into a repeatable test — and hybrid replay.

await client.startEnhancedRecording();

// ... user interacts with the device ...

const actions = await client.finalizeEnhancedRecording();
console.log(client.exportEnhancedRecording()); // formatted JSON for debugging
MethodDescription
startEnhancedRecording()Begin recording with element context. Async — it pre-warms the element lookup so the first tap is captured accurately; disable your record button until it resolves.
stopEnhancedRecording()Stop recording and return the captured EnhancedRecordedAction[].
finalizeEnhancedRecording(settleMs?)Stop recording, wait for the screen to settle (default 300 ms), capture a final end-state screenshot, and return the actions. Prefer this over stopEnhancedRecording() when the recording will be used for AI test generation or visual comparison.
exportEnhancedRecording()Return the current recording as a formatted JSON string — handy for debugging or sharing what was recorded.

To let users delete a step from a recording (e.g. in a review UI), use the standalone removeActionAt(actions, index) export — it removes the action at index (including the whole gesture, when the action is part of one) and returns a new array, so it works with React state or imported recordings.

Stream Stats

Inspect stream health and negotiated quality:

MethodDescription
getStreamStats()Current decoder statistics: { fps, framesDecoded, framesDropped, decodeErrors, decoderState, decoderType }, or null before the stream starts. Works with both WebCodecs and MSE decoders.
getPreferredCodec()The negotiated video codec: 'h264' or 'h265'.
getQualityTier()The name of the current adaptive-quality tier.

Cleanup

Call destroy() when you are done with a client instance:

client.destroy();

The destroy() method is idempotent — it checks an internal this.destroyed flag and returns immediately if the client has already been destroyed. This means it is safe to call destroy() multiple times, for example in both a cleanup handler and a component unmount.

Internally, destroy() closes the WebSocket connection, stops video decoding, removes all event listeners, and clears the container element.

Browser Compatibility

Check whether the current browser supports the SDK before rendering:

import { isSupported, getCompatibilityInfo } from '@vibeview/sdk';

if (!isSupported()) {
  const info = getCompatibilityInfo();
  console.warn(info.recommendation);
}

The SDK requires WebCodecs (or MSE as a fallback), WebSocket, and Canvas support.

Backward Compatibility

The SDK maintains strict backward compatibility. Published exports are never removed or renamed. If a type or function needs to change, a new export is added alongside the existing one. This ensures that applications built against earlier versions of the SDK continue to work after upgrades.

Tips

  • Use autoStart: true for demos and embedded docs where you want the simulator to appear immediately.
  • Use readOnly: true for presentation or documentation contexts where viewers should not interact with the device.
  • Use screenOnly: true to remove device chrome and show just the simulator screen, which is useful for tight layouts.
  • Set decoder: 'mse' if you need to support older browsers that lack WebCodecs.
  • The sessionId option lets you connect multiple clients to the same running session, which is useful for shared viewing scenarios.
  • After changing SDK source types locally, rebuild with cd sdk && yarn build before consuming the updated package.