New: Introducing PHP and Composer Support.Read the Announcement
Socket
Book a DemoInstallSign in
Socket

yoto-nodejs-client

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yoto-nodejs-client

(Unofficial) Node.js client for the Yoto API with automatic token refresh, MQTT device communication, and TypeScript support

Source
npmnpm
Version
0.0.2
Version published
Maintainers
1
Created
Source

yoto-nodejs-client

latest version Actions Status

downloads Types in JS neostandard javascript style Socket Badge

A comprehensive Node.js client for the Yoto API with automatic token refresh, MQTT device communication, and full TypeScript support.

Yoto

npm install yoto-nodejs-client

Usage

import { YotoClient } from 'yoto-nodejs-client'

// Authenticate using device flow (CLI/server applications)
const deviceCodeResponse = await YotoClient.requestDeviceCode({
  clientId: 'your-client-id'
})

console.log(`Visit ${deviceCodeResponse.verification_uri_complete}`)
console.log(`Enter code: ${deviceCodeResponse.user_code}`)

// Poll for token
const tokenResponse = await YotoClient.exchangeToken({
  grantType: 'urn:ietf:params:oauth:grant-type:device_code',
  deviceCode: deviceCodeResponse.device_code,
  clientId: 'your-client-id'
})

// Create client with automatic token refresh
const client = new YotoClient({
  clientId: 'your-client-id',
  refreshToken: tokenResponse.refresh_token,
  accessToken: tokenResponse.access_token,
  onTokenRefresh: async (event) => {
    // REQUIRED: Persist tokens when they refresh
    await saveTokens({
      accessToken: event.accessToken,
      refreshToken: event.refreshToken,
      expiresAt: event.expiresAt
    })
  }
})

// Get devices
const { devices } = await client.getDevices()
console.log('Your devices:', devices)

// Get device status
const status = await client.getDeviceStatus({ 
  deviceId: devices[0].deviceId 
})
console.log('Battery:', status.batteryLevelPercentage, '%')

// Get user's MYO content
const myoContent = await client.getUserMyoContent()
console.log('Your content:', myoContent)

// Connect to device via MQTT for real-time control
const mqtt = await client.createMqttClient({
  deviceId: devices[0].deviceId
})

mqtt.on('events', (message) => {
  console.log('Playing:', message.trackTitle)
})

mqtt.on('status', (message) => {
  console.log('Volume:', message.volume, '%')
})

await mqtt.connect()
await mqtt.setVolume(50)
await mqtt.setAmbientHex('#FF0000')

API

Authentication

YotoClient.requestDeviceCode({ clientId, [scope], [audience] })

Start the OAuth2 Device Authorization flow for CLI/server applications. Returns a device code and user verification URL.

  • clientId - Your OAuth client ID
  • scope - OAuth scopes (default: 'openid profile offline_access')
  • audience - Token audience (default: 'https://api.yotoplay.com')

See Yoto API: Device Code

const response = await YotoClient.requestDeviceCode({
  clientId: 'your-client-id'
})

console.log(`Visit: ${response.verification_uri_complete}`)
console.log(`Or go to ${response.verification_uri} and enter: ${response.user_code}`)

YotoClient.exchangeToken({ grantType, ...params })

Exchange authorization code, refresh token, or device code for access tokens.

  • grantType - 'authorization_code', 'refresh_token', or 'urn:ietf:params:oauth:grant-type:device_code'
  • code - Authorization code (for authorization_code grant)
  • refreshToken - Refresh token (for refresh_token grant)
  • deviceCode - Device code (for device code grant)
  • clientId - OAuth client ID
  • redirectUri - Redirect URI (for authorization_code grant)
  • codeVerifier - PKCE code verifier (optional)

See Yoto API: Token Exchange

// Exchange device code
const tokens = await YotoClient.exchangeToken({
  grantType: 'urn:ietf:params:oauth:grant-type:device_code',
  deviceCode: response.device_code,
  clientId: 'your-client-id'
})

// Refresh token
const refreshed = await YotoClient.exchangeToken({
  grantType: 'refresh_token',
  refreshToken: tokens.refresh_token,
  clientId: 'your-client-id'
})

YotoClient.getAuthorizeUrl({ clientId, redirectUri, responseType, state, ...params })

Get authorization URL for browser-based OAuth flow. Returns a URL string to redirect users to.

See Yoto API: Authorization

Client Instance

new YotoClient({ clientId, refreshToken, accessToken, onTokenRefresh, [options] })

Create a new Yoto API client with automatic token refresh.

  • clientId - OAuth client ID
  • refreshToken - OAuth refresh token
  • accessToken - Initial access token (JWT)
  • onTokenRefresh - REQUIRED callback for token refresh events. You MUST persist tokens here.
  • bufferSeconds - Seconds before expiration to refresh (default: 30)
  • userAgent - Optional user agent string to identify your application
  • defaultRequestOptions - Optional default undici request options (dispatcher, timeouts, etc.) applied to all requests
  • onRefreshStart - Optional callback when refresh starts
  • onRefreshError - Optional callback for transient refresh errors
  • onInvalid - Optional callback when refresh token is permanently invalid
const client = new YotoClient({
  clientId: 'your-client-id',
  refreshToken: 'stored-refresh-token',
  accessToken: 'stored-access-token',
  userAgent: 'MyApp/1.0.0',  // Optional - identifies your application
  defaultRequestOptions: {    // Optional - undici request options for all requests
    bodyTimeout: 30000,       // 30 second timeout
    headersTimeout: 10000,    // 10 second header timeout
    // dispatcher, signal, etc.
  },
  onTokenRefresh: async ({ accessToken, refreshToken, expiresAt }) => {
    // Save to database, file, etc.
    await db.saveTokens({ accessToken, refreshToken, expiresAt })
  }
})

Request Options

All API methods accept an optional requestOptions parameter that allows you to override the default undici request options for individual requests. This is useful for setting custom timeouts, using a specific dispatcher, or aborting requests.

// Override timeout for a specific request
const content = await client.getContent({ 
  cardId: '5WsQg',
  requestOptions: {
    bodyTimeout: 60000,  // 60 second timeout for this request only
    headersTimeout: 20000
  }
})

// Use AbortSignal to cancel requests
const controller = new AbortController()
setTimeout(() => controller.abort(), 5000)

try {
  const devices = await client.getDevices({
    requestOptions: { signal: controller.signal }
  })
} catch (err) {
  if (err.name === 'AbortError') {
    console.log('Request was aborted')
  }
}

// Use custom dispatcher for connection pooling
import { Agent } from 'undici'
const agent = new Agent({ connections: 10 })

const status = await client.getDeviceStatus({
  deviceId: 'abc123',
  requestOptions: { dispatcher: agent }
})

Available Request Options:

  • bodyTimeout - Body timeout in milliseconds
  • headersTimeout - Headers timeout in milliseconds
  • signal - AbortSignal to cancel the request
  • dispatcher - Custom undici dispatcher (for connection pooling, proxies, etc.)
  • reset - Reset connection after request
  • throwOnError - Throw on HTTP error status codes
  • idempotent - Whether the requests can be safely retried
  • blocking - Whether the response is expected to take a long time
  • Other undici RequestOptions (see undici documentation)

Content API

await client.getContent({ cardId, [timezone], [signingType], [playable] })

Get content/card details including metadata, chapters, and optionally playback URLs.

See Yoto API: Get Content

const content = await client.getContent({ 
  cardId: '5WsQg',
  playable: true  // Include signed playback URLs
})

console.log(content.title)
console.log(content.chapters)

await client.getUserMyoContent({ [showDeleted] })

Get user's MYO (Make Your Own) content library.

See Yoto API: Get User's MYO Content

const myoContent = await client.getUserMyoContent({ 
  showDeleted: false 
})

myoContent.cards.forEach(card => {
  console.log(`${card.metadata.title} - ${card.chapters.length} chapters`)
})

await client.createOrUpdateContent({ content })

Create new content or update existing content by cardId.

See Yoto API: Create or Update Content

const newCard = await client.createOrUpdateContent({
  content: {
    title: 'My Story',
    chapters: [
      {
        title: 'Chapter 1',
        tracks: [
          {
            title: 'Part 1',
            key: 'upload-id-from-audio-upload'
          }
        ]
      }
    ]
  }
})

console.log('Created card:', newCard.cardId)

await client.deleteContent({ cardId })

Delete content/card.

See Yoto API: Delete Content

await client.deleteContent({ cardId: '5WsQg' })

Devices API

await client.getDevices()

Get all devices for authenticated user.

See Yoto API: Get Devices

const { devices } = await client.getDevices()

devices.forEach(device => {
  console.log(`${device.name} (${device.deviceId}) - ${device.online ? 'online' : 'offline'}`)
})

await client.getDeviceStatus({ deviceId })

Get current status of a specific device including battery, volume, active card, etc.

See Yoto API: Get Device Status

const status = await client.getDeviceStatus({ 
  deviceId: 'abc123' 
})

console.log('Battery:', status.batteryLevelPercentage, '%')
console.log('Charging:', status.isCharging)
console.log('Volume:', status.userVolumePercentage, '%')
console.log('Active card:', status.activeCard)

await client.getDeviceConfig({ deviceId })

Get device configuration including settings, timezone, shortcuts, etc.

See Yoto API: Get Device Config

const config = await client.getDeviceConfig({ 
  deviceId: 'abc123' 
})

console.log('Name:', config.device.name)
console.log('Day time:', config.device.config.dayTime)
console.log('Night time:', config.device.config.nightTime)
console.log('Max volume:', config.device.config.maxVolumeLimit)

await client.updateDeviceConfig({ deviceId, configUpdate })

Update device configuration settings.

See Yoto API: Update Device Config

await client.updateDeviceConfig({
  deviceId: 'abc123',
  configUpdate: {
    name: 'Bedroom Player',
    config: {
      dayTime: '07:00',
      nightTime: '19:00',
      maxVolumeLimit: '80'
    }
  }
})

await client.updateDeviceShortcuts({ deviceId, shortcutsUpdate })

Update device shortcuts configuration (beta feature).

See Yoto API: Update Shortcuts

await client.sendDeviceCommand({ deviceId, command })

Send MQTT command to device via HTTP API (alternative to MQTT client).

See Yoto API: Send Device Command

await client.sendDeviceCommand({
  deviceId: 'abc123',
  command: {
    volume: 50
  }
})

Family Library Groups API

await client.getGroups()

Get all family library groups.

See Yoto API: Get Groups

const groups = await client.getGroups()

groups.forEach(group => {
  console.log(`${group.name}: ${group.items.length} items`)
})

await client.createGroup({ group })

Create a new family library group.

See Yoto API: Create Group

const group = await client.createGroup({
  group: {
    name: 'Bedtime Stories',
    imageId: 'fp-cards',
    items: [
      { contentId: '5WsQg' },
      { contentId: '7KpLq' }
    ]
  }
})

await client.getGroup({ groupId })

Get a specific group by ID.

See Yoto API: Get a Group

await client.updateGroup({ groupId, group })

Update an existing group.

See Yoto API: Update Group

await client.deleteGroup({ groupId })

Delete a group permanently.

See Yoto API: Delete Group

Family API

await client.getFamilyImages()

Get list of uploaded family images.

See Yoto API: Get Family Images

const { images } = await client.getFamilyImages()

images.forEach(image => {
  console.log(`${image.name || 'Unnamed'}: ${image.imageId}`)
})

await client.getAFamilyImage({ imageId, size })

Get signed URL for a family image.

See Yoto API: Get a Family Image

const { imageUrl } = await client.getAFamilyImage({
  imageId: 'abc123hash',
  size: '640x480'  // or '320x320'
})

console.log('Image URL:', imageUrl)

await client.uploadAFamilyImage({ imageData })

Upload a family image for use across Yoto features.

See Yoto API: Upload Family Image

import { readFile } from 'fs/promises'

const imageData = await readFile('./family-photo.jpg')
const result = await client.uploadAFamilyImage({ imageData })

console.log('Image ID:', result.imageId)

Icons API

await client.getPublicIcons()

Get list of public display icons available to all users.

See Yoto API: Get Public Icons

const { displayIcons } = await client.getPublicIcons()

displayIcons.forEach(icon => {
  console.log(`${icon.title}: ${icon.displayIconId}`)
})

await client.getUserIcons()

Get user's custom uploaded icons.

See Yoto API: Get User Icons

await client.uploadIcon({ imageData, [autoConvert], [filename] })

Upload a custom 16×16px display icon.

See Yoto API: Upload Custom Icon

import { readFile } from 'fs/promises'

const imageData = await readFile('./my-icon.png')
const result = await client.uploadIcon({
  imageData,
  autoConvert: true,  // Auto-resize and process
  filename: 'my-custom-icon'
})

console.log('Icon ID:', result.displayIcon.displayIconId)

Media API

await client.getAudioUploadUrl({ sha256, [filename] })

Get signed URL for uploading audio files. Files are deduplicated by SHA256 hash.

See Yoto API: Get Audio Upload URL

import { createHash } from 'crypto'
import { readFile } from 'fs/promises'

const audioData = await readFile('./story.mp3')
const sha256 = createHash('sha256').update(audioData).digest('hex')

const { upload } = await client.getAudioUploadUrl({ 
  sha256,
  filename: 'story.mp3'
})

if (upload.uploadUrl) {
  // File doesn't exist, upload it
  await fetch(upload.uploadUrl, {
    method: 'PUT',
    body: audioData
  })
}

// Use upload.uploadId in content creation

await client.uploadCoverImage({ [imageData], [imageUrl], [coverType], [autoConvert], [filename] })

Upload a cover image for content cards.

See Yoto API: Upload Cover Image

import { readFile } from 'fs/promises'

const imageData = await readFile('./cover.jpg')
const { coverImage } = await client.uploadCoverImage({
  imageData,
  coverType: 'default',  // 638×1011px
  autoConvert: true
})

console.log('Cover image ID:', coverImage.mediaId)

MQTT Client

await client.createMqttClient({ deviceId, [options] })

Create an MQTT client for real-time device communication and control.

See Yoto MQTT Documentation

const mqtt = await client.createMqttClient({
  deviceId: 'abc123',
  autoResubscribe: true,
  keepAliveSeconds: 1200
})

// Listen for real-time events
mqtt.on('events', (message) => {
  console.log('Track:', message.trackTitle)
  console.log('Card:', message.cardTitle)
  console.log('Status:', message.playbackStatus)
})

// Listen for status updates
mqtt.on('status', (message) => {
  console.log('Volume:', message.volume)
  console.log('Battery:', message.batteryLevel)
  console.log('Charging:', message.charging)
})

// Listen for command responses
mqtt.on('response', (message) => {
  console.log('Command response:', message)
})

// Connect to device
await mqtt.connect()

// Control device
await mqtt.setVolume(50)
await mqtt.setAmbientHex('#FF0000')
await mqtt.setSleepTimer(30)  // 30 minutes
await mqtt.startCard({ cardId: '5WsQg' })
await mqtt.pauseCard()
await mqtt.resumeCard()
await mqtt.stopCard()

// Disconnect when done
await mqtt.disconnect()

MQTT Events

The MQTT client emits three types of messages:

  • events - Real-time playback events (track changes, play/pause, volume adjustments)
  • status - Device status updates (battery, configuration, online state)
  • response - Command confirmation responses

MQTT Methods

  • await mqtt.connect() - Connect to device MQTT broker
  • await mqtt.disconnect() - Disconnect from broker
  • await mqtt.setVolume(volume) - Set volume (0-100)
  • await mqtt.setAmbientHex(hex) - Set ambient light color (e.g., '#FF0000')
  • await mqtt.setSleepTimer(minutes) - Set sleep timer (0 to disable)
  • await mqtt.startCard({ cardId, chapterKey, trackKey }) - Start playing a card
  • await mqtt.pauseCard() - Pause current playback
  • await mqtt.resumeCard() - Resume playback
  • await mqtt.stopCard() - Stop playback
  • await mqtt.reboot() - Reboot device

CLI Tools

The library includes CLI tools for authentication and data inspection:

Authentication

# Get initial tokens (device flow)
node bin/auth.js --output .env

# Refresh tokens
node bin/refresh-token.js

# Show token info
node bin/token-info.js

Data Inspection

# List all devices
node bin/devices.js

# Get device details with config
node bin/devices.js --device-id abc123

# Get device status only
node bin/devices.js --device-id abc123 --status

# Connect to MQTT and listen for messages
node bin/devices.js --device-id abc123 --mqtt

# Sample MQTT messages for 10 seconds
node bin/devices.js --device-id abc123 --mqtt --mqtt-stop-after-seconds 10

# List all MYO content
node bin/content.js

# Get specific card details
node bin/content.js --card-id 5WsQg

# Get card with playable URLs
node bin/content.js --card-id 5WsQg --playable

See also

License

MIT

Keywords

yoto

FAQs

Package last updated on 21 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts