Skip to main content

HighlightsClient

The HighlightsClient class provides methods for managing user Bible highlights through the YouVersion Platform API. All endpoints require OAuth authentication with appropriate scopes.
All HighlightsClient methods require OAuth authentication. See the Authentication guide for implementing the PKCE flow.

Constructor

import { ApiClient, HighlightsClient } from '@youversion/platform-core';

const apiClient = new ApiClient({ appKey: 'your-app-key' });
const highlightsClient = new HighlightsClient(apiClient);
client
ApiClient
required
An instance of ApiClient used to make HTTP requests.

Authentication

Highlights endpoints require a valid OAuth access token. You can provide the token in two ways:
  1. Pass as parameter - Explicitly pass the lat (long access token) parameter to each method
  2. Global configuration - Set the token in YouVersionPlatformConfiguration.accessToken
import { YouVersionPlatformConfiguration } from '@youversion/platform-core';

// Option 1: Set globally (recommended)
YouVersionPlatformConfiguration.saveAuthData(
  accessToken,
  refreshToken,
  idToken,
  expiryDate
);

// Now all methods use the global token
const highlights = await highlightsClient.getHighlights();

// Option 2: Pass explicitly
const highlights = await highlightsClient.getHighlights(undefined, accessToken);

Methods

getHighlights()

Fetches a collection of highlights for the authenticated user. Returns one color per verse (no ranges). Requires OAuth scope: read_highlights
async getHighlights(
  options?: GetHighlightsOptions,
  lat?: string
): Promise<Collection<Highlight>>
options
GetHighlightsOptions
Optional query parameters for filtering highlights.
lat
string
Optional long access token. If not provided, uses token from YouVersionPlatformConfiguration.accessToken.
Returns
Promise<Collection<Highlight>>
Collection of user highlights.

Examples

// Get all highlights for the authenticated user
const highlights = await highlightsClient.getHighlights();

console.log(`Total highlights: ${highlights.data.length}`);

highlights.data.forEach(highlight => {
  console.log(
    `${highlight.passage_id} in version ${highlight.version_id}: #${highlight.color}`
  );
});

createHighlight()

Creates or updates a highlight on a passage. Verse ranges may be used in the passage_id. Requires OAuth scope: write_highlights
async createHighlight(
  data: CreateHighlight,
  lat?: string
): Promise<Highlight>
data
CreateHighlight
required
The highlight data to create or update.
lat
string
Optional long access token. If not provided, uses token from YouVersionPlatformConfiguration.accessToken.
Returns
Promise<Highlight>
The created or updated highlight.

Examples

// Highlight John 3:16 in yellow
const highlight = await highlightsClient.createHighlight({
  version_id: 111,
  passage_id: 'JHN.3.16',
  color: 'ffff00' // Yellow
});

console.log(`Created highlight: ${highlight.passage_id}`);

deleteHighlight()

Clears highlights for a passage. Removes all highlights matching the passage ID and optional version ID. Requires OAuth scope: write_highlights
async deleteHighlight(
  passageId: string,
  options?: DeleteHighlightOptions,
  lat?: string
): Promise<void>
passageId
string
required
The passage identifier (USFM format, e.g., "MAT.1.1" or "MAT.1.1-5")
options
DeleteHighlightOptions
Optional parameters for deletion.
lat
string
Optional long access token. If not provided, uses token from YouVersionPlatformConfiguration.accessToken.
Returns
Promise<void>
Promise that resolves when highlights are deleted (204 No Content response).

Examples

// Remove highlight from John 3:16
await highlightsClient.deleteHighlight('JHN.3.16');

console.log('Highlight removed');

Complete Example

import {
  ApiClient,
  HighlightsClient,
  BibleClient,
  YouVersionPlatformConfiguration
} from '@youversion/platform-core';

// Initialize clients
const apiClient = new ApiClient({
  appKey: process.env.YOUVERSION_APP_KEY!,
});
const highlightsClient = new HighlightsClient(apiClient);
const bibleClient = new BibleClient(apiClient);

// Assume user has authenticated via OAuth
const accessToken = 'user-oauth-access-token';
YouVersionPlatformConfiguration.saveAuthData(
  accessToken,
  'refresh-token',
  'id-token',
  new Date(Date.now() + 3600000) // 1 hour from now
);

// Get user's existing highlights
const highlights = await highlightsClient.getHighlights({
  version_id: 111 // NIV
});

console.log(`User has ${highlights.data.length} highlights in NIV`);

// Highlight a new verse in yellow
await highlightsClient.createHighlight({
  version_id: 111,
  passage_id: 'JHN.3.16',
  color: 'ffff00'
});

console.log('Highlighted John 3:16 in yellow');

// Get the passage content with highlight
const passage = await bibleClient.getPassage(111, 'JHN.3.16');
console.log(`\n${passage.reference}`);
console.log(passage.content);

// Update highlight color to green
await highlightsClient.createHighlight({
  version_id: 111,
  passage_id: 'JHN.3.16',
  color: '00ff00' // Green
});

console.log('Changed highlight color to green');

// Highlight a range of verses
await highlightsClient.createHighlight({
  version_id: 111,
  passage_id: 'PSA.23.1-6', // Entire Psalm 23
  color: '0000ff' // Blue
});

console.log('Highlighted Psalm 23 in blue');

// Get all highlights again
const updated = await highlightsClient.getHighlights({
  version_id: 111
});

console.log(`\nNow user has ${updated.data.length} highlights`);

// Group by color
const byColor = updated.data.reduce((acc, h) => {
  if (!acc[h.color]) acc[h.color] = [];
  acc[h.color].push(h.passage_id);
  return acc;
}, {} as Record<string, string[]>);

Object.entries(byColor).forEach(([color, passages]) => {
  console.log(`\nColor #${color}:`);
  passages.forEach(p => console.log(`  - ${p}`));
});

// Remove a highlight
await highlightsClient.deleteHighlight('JHN.3.16', {
  version_id: 111
});

console.log('\nRemoved highlight from John 3:16');

Best Practices

Set the access token globally instead of passing it to every method:
import { YouVersionPlatformConfiguration } from '@youversion/platform-core';

// After successful OAuth authentication
YouVersionPlatformConfiguration.saveAuthData(
  accessToken,
  refreshToken,
  idToken,
  expiryDate
);

// Now all methods work without explicit token
const highlights = await highlightsClient.getHighlights();
await highlightsClient.createHighlight({ ... });
Always handle authentication and authorization errors:
try {
  const highlights = await highlightsClient.getHighlights();
} catch (error) {
  if (error instanceof Error) {
    const httpError = error as Error & { status?: number };
    
    if (httpError.status === 401) {
      console.error('Authentication required');
      // Redirect to login
    } else if (httpError.status === 403) {
      console.error('Insufficient permissions');
      // Request additional scopes
    }
  }
}
Ensure colors are valid 6-digit hex codes:
function isValidColor(color: string): boolean {
  return /^[0-9a-f]{6}$/i.test(color);
}

function normalizeColor(color: string): string {
  // Remove # if present
  color = color.replace(/^#/, '');
  
  if (!isValidColor(color)) {
    throw new Error('Invalid color format');
  }
  
  return color.toLowerCase();
}

const userColor = '#FFFF00';
const normalized = normalizeColor(userColor); // 'ffff00'

await highlightsClient.createHighlight({
  version_id: 111,
  passage_id: 'JHN.3.16',
  color: normalized
});
When creating multiple highlights, batch them efficiently:
const versesToHighlight = [
  'JHN.3.16',
  'PSA.23.1',
  'ROM.8.28'
];

const color = 'ffff00'; // Yellow

// Create all highlights
await Promise.all(
  versesToHighlight.map(passage_id =>
    highlightsClient.createHighlight({
      version_id: 111,
      passage_id,
      color
    })
  )
);

console.log('Created all highlights');
Keep a local cache of highlights for offline access:
async function syncHighlights(versionId: number) {
  // Fetch from API
  const highlights = await highlightsClient.getHighlights({
    version_id: versionId
  });
  
  // Store locally
  localStorage.setItem(
    `highlights-${versionId}`,
    JSON.stringify(highlights.data)
  );
  
  return highlights.data;
}

async function getHighlightsCached(versionId: number) {
  // Try local first
  const cached = localStorage.getItem(`highlights-${versionId}`);
  
  if (cached) {
    return JSON.parse(cached);
  }
  
  // Fetch and cache
  return await syncHighlights(versionId);
}
Offer users a palette of predefined colors:
const HIGHLIGHT_COLORS = {
  yellow: { name: 'Yellow', hex: 'ffff00' },
  green: { name: 'Green', hex: '00ff00' },
  blue: { name: 'Blue', hex: '0000ff' },
  red: { name: 'Red', hex: 'ff0000' },
  orange: { name: 'Orange', hex: 'ffa500' },
  purple: { name: 'Purple', hex: '800080' },
  pink: { name: 'Pink', hex: 'ffc0cb' },
};

// Use in UI
Object.entries(HIGHLIGHT_COLORS).forEach(([key, { name, hex }]) => {
  // Render color button with style={`background: #${hex}`}
});

Validation

The client validates all inputs using Zod schemas:
  • version_id: Must be a positive integer
  • passage_id: Must be a non-empty string
  • color: Must be exactly 6 hex characters (without #)
try {
  // ✅ Valid
  await highlightsClient.createHighlight({
    version_id: 111,
    passage_id: 'JHN.3.16',
    color: 'ffff00'
  });
  
  // ❌ Invalid - throws error
  await highlightsClient.createHighlight({
    version_id: -1, // Must be positive
    passage_id: '', // Must be non-empty
    color: '#ffff00' // No # allowed
  });
  
  // ❌ Invalid color format
  await highlightsClient.createHighlight({
    version_id: 111,
    passage_id: 'JHN.3.16',
    color: 'yellow' // Must be hex
  });
} catch (error) {
  console.error(error.message);
}

OAuth Scopes

Highlights endpoints require specific OAuth scopes:
  • read_highlights - Required for getHighlights()
  • write_highlights - Required for createHighlight() and deleteHighlight()
See the Authentication guide for implementing OAuth with the correct scopes.

Type Definitions

GetHighlightsOptions

highlights.ts:9
export type GetHighlightsOptions = {
  version_id?: number;
  passage_id?: string;
};

DeleteHighlightOptions

highlights.ts:16
export type DeleteHighlightOptions = {
  version_id?: number;
};

Highlight

export type Highlight = {
  version_id: number;
  passage_id: string;
  color: string; // 6-digit hex without #
};

CreateHighlight

export type CreateHighlight = {
  version_id: number;
  passage_id: string;
  color: string; // 6-digit hex without #
};

Build docs developers (and LLMs) love