Skip to content

gwp developer guide

Andre Lafleur edited this page May 10, 2026 · 13 revisions

Genetec Web Player developer guide

The Genetec Web Player (GWP) is a JavaScript/TypeScript library designed to embed live and playback video streams from Genetec Security Center™ into custom web applications. It offers advanced video streaming capabilities using WebSockets and Media Source Extensions, providing an easy-to-use API while abstracting the complexities of managing streams, codecs, and security.

This guide provides detailed instructions for integrating the GWP into your application, including setup, authentication, and usage examples for advanced features like PTZ control, timeline management, and diagnostics.

Additional documentation:

  • GWP API reference: complete technical API reference with all interfaces, methods, properties, events, and enumerations.
  • Sample application: comprehensive working example demonstrating all GWP features, useful for testing and debugging.

Architecture

  • Client:

    • GWP runs in the browser, using WebSockets and Media Source Extensions for streaming.
    • All video/audio decoding is handled by the browser, leveraging hardware acceleration when available.
  • Server:

    • The Media Gateway role in Security Center streams video/audio and handles transcoding if needed.
    • The web server hosting your application must be able to reach the Media Gateway.
  • Authentication:

    • Uses Security Center users for secure token retrieval.
    • All user privileges are enforced by the Media Gateway.
  • Data Flow:

    1. Browser (GWP) establishes a secure WebSocket (WSS) to the Media Gateway.
    2. Token retrieval is handled via a callback function.
    3. Video/audio streams are delivered directly to the browser.

Features

  • Live and Playback Video Streaming: Access real-time and recorded video feeds.
  • Audio Support: Stream AAC audio where supported.
  • PTZ Camera Control: Low-latency Pan-Tilt-Zoom control.
  • Dynamic Stream Selection: Adaptive resolution and bitrate adjustment based on player size.
  • Digital Zoom: Enhance video regions for detailed views.
  • Fisheye Dewarping: Correct fisheye distortions for a traditional PTZ-like experience.
  • Timeline API: Access bookmarks and motion detection events.
  • Diagnostics: Tools for debugging and monitoring.

Prerequisites

  1. Media Gateway Role:

    • The Media Gateway Role must be configured in Security Center. See the Media Gateway Developer Guide for setup instructions.
    • Open ports 80 and 443 for public access.
    • Ensure the Media Gateway and GWP library versions are compatible.
  2. Authentication:

    • Security Center user credentials.
  3. Environment Requirements:

    • Supported Browsers: Chrome, Firefox, Edge, Safari.
  4. Camera GUIDs: Unique identifiers for the cameras you wish to stream.

Security Center privileges

To use the Genetec Web Player, users must have the appropriate Security Center privileges configured.

Important

A local user account with the necessary privileges listed below will work. The user must also have access rights to the partition where the camera is located.

Required privileges

These requirements apply before a GWP application can retrieve a token for a camera:

Authentication requirements

  • A valid Security Center user name and password, or another supported authentication method.
  • A valid SDK certificate.
  • A Security Center system with a Media SDK license.

Web App privileges

  • Live hit monitoring: Allows the user to connect through the Web App video path used by Media Gateway.

Action privileges: cameras

The user must have at least one of these privileges on the requested camera:

  • View live video: Required to view live video streams from cameras (when using playLive()).
  • View playback: Required to view recorded/playback video from cameras (when using seek() or playback features).

Optional privileges (feature-specific)

These privileges are only required if your application uses the corresponding features:

PTZ motor privileges (under View live video)

For PTZ camera control functionality, the following table maps GWP PTZ methods to their required Security Center privileges:

GWP PTZ Method(s) Required Privilege Description
startPanTilt(), stopPanTilt(), startZoom(), stopZoom(), stop(), goHome() Perform basic operations Allows basic PTZ operations (pan, tilt, zoom, and stop movements)
goToPreset(preset) Use presets Allows the user to move the camera to preset positions
runPattern(pattern) Use patterns Allows the user to run camera movement patterns
lock(), unlock() Lock PTZ Allows the user to lock and unlock PTZ controls
startFocus(), stopFocus(), startIris(), stopIris() Change focus and iris settings Allows the user to adjust camera focus and iris settings

Note

PTZ privileges are hierarchical. The parent privilege "View live video" must be granted before any PTZ motor privileges can take effect.

Configuration Note: All privileges can be configured in Security Center Config Tool under User Management. Ensure that users or user groups are granted the necessary privileges and have access rights to the partitions containing the cameras they need to access.

Quick start

This section provides a minimal working example to get you started quickly. For detailed explanations, see the subsequent sections.

Include GWP in your HTML

<!DOCTYPE html>
<html>
<head>
    <title>GWP Quick Start</title>
</head>
<body>
    <div id="playerContainer" style="width: 640px; height: 480px;"></div>
    <script src="https://<YourMediaGatewayAddress>/media/v2/files/gwp.js"></script>
    <script src="app.js"></script>
</body>
</html>

Create your application (app.js)

// Configuration
const mediaGatewayEndpoint = 'https://<YourMediaGatewayAddress>/media';
const cameraGuid = '00000000-0000-0000-0000-000000000000'; // Replace with your camera GUID
const username = 'admin';
const sdkCertificate = 'YourSDKCertificate'; // From Security Center license
const password = 'yourPassword';

// Token retrieval function
const getTokenFct = async (cameraId) => {
    const response = await fetch(`${mediaGatewayEndpoint}/v2/token/${cameraId}`, {
        credentials: 'include',
        headers: {
            'Authorization': `Basic ${btoa(username + ";" + sdkCertificate + ":" + password)}`
        }
    });

    const responseText = await response.text();

    if (!response.ok) {
        throw new Error(`Failed to fetch token: ${response.status} ${responseText || response.statusText}`);
    }

    return responseText;
};

// Initialize player
async function startPlayer() {
    try {
        // Create player instance
        const divContainer = document.getElementById('playerContainer');
        const webPlayer = gwp.buildPlayer(divContainer);

        // Register error handler
        webPlayer.onErrorStateRaised.register((error) => {
            console.error(`Error ${error.errorCode}: ${error.value}`);
        });

        // Start and connect to camera
        await webPlayer.start(cameraGuid, mediaGatewayEndpoint, getTokenFct);

        // Play live video
        webPlayer.playLive();

        console.log('Player started successfully!');
    } catch (error) {
        console.error('Failed to start player:', error);
    }
}

// Start when page loads
startPlayer();

Configure CORS (if needed)

If you see CORS errors, first verify that your application calls the GWP endpoints exposed by Media Gateway. If your deployment enforces an explicit origin policy, configure the Media Gateway to allow your origin. See the Troubleshooting section.

Next steps: Continue reading for detailed information on authentication, privileges, PTZ control, playback, and advanced features.

Installation

Add GWP to your project

The GWP library can be included in two ways:

Using a script tag

<script src="https://<MediaGatewayAddress>/media/v2/files/gwp.js"></script>

Using a CommonJS module

const gwp = require('<MediaGatewayAddress>/media/v2/files/gwp');

Important

It is strongly recommended to load the GWP library directly from the Media Gateway server that your application connects to. While you can download and cache the gwp.js file separately, this approach is not recommended because using a stale or mismatched GWP library may result in compatibility issues, broken functionality, or unexpected behavior.

Record the GWP library version

Use gwp.version() to retrieve the GWP library version when troubleshooting or reporting an issue:

console.log(gwp.version());

For compatibility, load gwp.js from the same Media Gateway endpoint that your application uses for token retrieval and streaming.

Media Gateway configuration

Roles and agents

In Security Center, a Role represents a specific task with its configuration, while Agents are servers assigned to perform that role's work. When you create a Media Gateway role in Security Center, every agent assigned to this role shares the same configuration.

The Genetec Web Player connects to a specific Media Gateway agent. You must provide the public address of this agent in the start() method.

Load balancing (multiple agents)

If you have multiple Media Gateway agents, you are responsible for implementing load balancing logic in your application. The GWP does not automatically load balance between agents.

Simple Approach: Alternate between agents in a round-robin fashion.

Advanced Load Balancing should consider:

  1. Current Server Load - Distribute connections evenly across all agents
  2. Resource Sharing - Streaming the same camera twice from the same agent is more efficient than using two different agents
  3. Network Topology - Avoid long-distance redirection; prefer geographically closer agents
  4. Agent Health - Monitor agent availability and route away from unhealthy agents

Example:

const mediaGatewayAgents = [
    'https://gateway1.example.com/media',
    'https://gateway2.example.com/media',
    'https://gateway3.example.com/media'
];

let currentAgentIndex = 0;

function getNextMediaGatewayAgent() {
    const agent = mediaGatewayAgents[currentAgentIndex];
    currentAgentIndex = (currentAgentIndex + 1) % mediaGatewayAgents.length;
    return agent;
}

// Use when starting player
const mediaGatewayEndpoint = getNextMediaGatewayAgent();
await webPlayer.start(cameraGuid, mediaGatewayEndpoint, getTokenFct);

Authentication

Token-based authentication

To connect to the Media Gateway and stream video, the GWP requires a security token. This token is obtained by authenticating with Security Center user credentials and a valid SDK certificate. Media Gateway issues the token only when the user has the Web App privilege "Live hit monitoring" and at least one of the camera privileges "View live video" or "View playback" on the requested camera.

Obtaining a token

Tokens can be obtained via the Media Gateway's /v2/token/{cameraId} endpoint.

API Endpoint:

GET /v2/token/{cameraId}

Headers:

  • Authorization: Basic <Base64(username;sdkCertificate:password)>

Example:

const getTokenFct = async (cameraId) => {
    const response = await fetch(`${mediaGatewayEndpoint}/v2/token/${cameraId}`, {
        credentials: 'include',
        headers: {
            'Authorization': `Basic ${btoa(username + ";" + sdkCertificate + ":" + password)}`
        }
    });

    const responseText = await response.text();

    if (!response.ok) {
        throw new Error(`Failed to fetch token: ${response.status} ${responseText || response.statusText}`);
    }

    return responseText;
};

Important

Do not hardcode credentials in browser-side code. Use server-side logic to fetch tokens securely: have your backend handle token requests with Security Center user credentials, then pass the token to the browser.

In summary:

  • GWP relies on Security Center users for authentication and token retrieval.
  • The token authorizes and scopes access to video streams.
  • The Media Gateway enforces all user privileges based on the Security Center user account used for token generation.

Creating and managing the player

Player life cycle

A player (or IWebPlayer) represents a single video stream displayed in your web page. The player goes through distinct states during its lifetime:

Instantiate the player

Players are anchored in an existing empty HTML div element on your web page.

const divContainer = document.getElementById('playerContainer');
const webPlayer = gwp.buildPlayer(divContainer);

At this stage:

  • The player displays a black background
  • No connection to Media Gateway has been established
  • The player tries to use as much space as possible in the div element
  • Now is the time to register event handlers before starting the player

Next steps: Either start the player or dispose of it.

Start the player

The start() method initializes the connection with a Media Gateway for a specific camera (but doesn't play anything until you call playLive() or seek()).

await webPlayer.start(cameraGuid, mediaGatewayEndpoint, getTokenFct);

Parameters:

  • cameraGuid: The unique identifier of the camera in 8-4-4-4-12 format (for example, "00000001-0000-babe-0000-080023e940c6")
  • mediaGatewayEndpoint: The Media Gateway's public address (for example, "https://hostname.com/media")
  • getTokenFct: A callback function returning a token (see Authentication)

This call returns a Promise:

  • Succeeds once initialization and connection to Media Gateway is complete
  • Fails if connection cannot be established (invalid parameters, network issues, or token problems)
  • You cannot use the player until the promise completes

Alternative: Use startWithService() for WebSocket multiplexing (see Advanced: Multiplexing Multiple Players)

Use the player

Once started, you can call player commands. The player accepts commands immediately and processes them asynchronously.

Playing a Live Stream:

webPlayer.playLive();

Playback Controls:

// Seek to a specific time
webPlayer.seek(new Date('2023-12-24T10:00:00Z'));

// Pause and Resume
webPlayer.pause();
webPlayer.resume();

// Adjust playback speed (0.01 to 100, or -100 to -0.01 for reverse)
webPlayer.setPlaySpeed(2);    // Fast-forward at 2x speed
webPlayer.setPlaySpeed(-6);   // Reverse playback at 6x speed

Other Controls:

// Enable audio
webPlayer.setAudioEnabled(true);

// Enable PTZ low-latency mode
webPlayer.setPtzMode(true);

// Toggle privacy protection
webPlayer.togglePrivacy();

// Show diagnostic overlay
webPlayer.showDebugOverlay(true);

Next steps: Either stop the player or dispose of it when done.

Stop the player

Calling stop() on a started player will stop and clear any stream currently being displayed.

webPlayer.stop();

After stopping:

  • No video will be displayed (black background)
  • You can start() again with a different camera or Media Gateway
  • It's generally better to reuse a player for performance and to avoid changing the web page layout

Dispose the player

Disposing will free all resources and remove everything from the HTML div element.

webPlayer.dispose();

Important

  • The player instance becomes completely unusable after disposal
  • Unregister all event handlers before disposing
  • The DOM container is cleared

Error handling

Overview

The GWP provides error events to help you handle issues such as network problems, invalid tokens, permission errors, or server outages. Proper error handling improves user experience and aids in troubleshooting.

Listening for errors

The player provides the onErrorStateRaised event that fires when an error occurs. Always register an error handler:

webPlayer.onErrorStateRaised.register((error) => {
    console.error(`Error ${error.errorCode}: ${error.value}`);

    if (error.isFatal) {
        // Fatal errors stop the player
        handleFatalError(error);
    } else {
        // Non-fatal errors may allow continued operation
        handleNonFatalError(error);
    }
});

Error event structure

The ErrorStatusEvent object contains:

  • errorCode (number): The error code from the ErrorCode enum
  • value (string): Textual description of the error (not localized)
  • isFatal (boolean): Indicates whether the error stops the player

Error codes

The GWP uses the following error codes (from the ErrorCode enum):

Error Code Value Description Suggested Action
Unknown 0 Unknown error Display generic error message and retry
ConnectionLost 2 Connection lost Attempt to reconnect or notify user
InsufficientDiskSpace 3 Server has disk space issues Notify user, contact administrator
ConnectionFailed 4 Connection failed Check network connectivity, retry
StreamNotFound 6 Stream not found Verify camera GUID, check camera availability
RequestTimedOut 9 Request timed out Retry operation
UnitPlaybackUnavailable 11 Video unit can't do playback Notify user that playback is unavailable
LiveCapacityExceeded 12 Live stream limit reached Notify user, try again later
PlaybackCapacityExceeded 13 Playback stream limit reached Notify user, try again later
UnsupportedEncoding 14 Unsupported codec Check camera configuration
DatabaseUpgradeRequired 15 Media Router database needs upgrade Contact administrator
InsufficientPrivilege 16 User lacks required privileges Check Security Center privileges, contact administrator
InsufficientCapability 17 Video unit cannot process command Check camera/server capabilities
MissingCertificate 18 Cannot decrypt encrypted stream Check encryption certificates
NotSupported 20 Command not supported Check feature availability
CantUsePrivateKey 21 Certificate missing private key Check certificate configuration
Mp4CodecNotSupported 22 Reserved value not used by GWP No action required
DeniedByServer 23 Server rejected the request Check permissions and configuration
NoTranscodingAllowed 24 Transcoding is prevented Check Media Gateway configuration
ForbiddenTransformation 32 Stream transformation requires transcoding Adjust stream settings or enable transcoding
CloudPlaybackFailure 33 Unable to play from cloud Check cloud configuration
UnsupportedOmnicastFederationRole 34 Omnicast Federation Role not supported Check federation configuration
UpdateSessionError 1000 Invalid stream state Restart player session
DeviceOffline 10000 Device is offline Verify that the camera or video unit is online
ConnectionError 10001 Signaling error Check network connectivity and retry
HlsPlaybackError 10002 HLS playback error Retry playback or check browser and stream compatibility
NoVideoRecording 10003 No video recording is available for HLS playback at the requested time Select a time with recorded video
OperationCanceled 10004 Live or playback request was interrupted before it could start Retry the requested operation
TooManyClients 10005 Device reached the maximum number of concurrent live streams Close another stream or try again later
WebRtcStreamingDenied 10006 WebRTC streaming is not allowed for this tenant Check tenant or Media Gateway configuration

Example: handling common errors

webPlayer.onErrorStateRaised.register((error) => {
    switch (error.errorCode) {
        case 16: // InsufficientPrivilege
            displayError('Access denied. You do not have permission to view this camera. Please contact your administrator.');
            break;

        case 2: // ConnectionLost
        case 4: // ConnectionFailed
            displayError('Network connection lost. Attempting to reconnect...');
            // Optionally implement retry logic
            break;

        case 6: // StreamNotFound
            displayError('Camera not found. Please verify the camera is online and try again.');
            break;

        case 9: // RequestTimedOut
            displayError('Request timed out. Please check your network connection and try again.');
            break;

        case 12: // LiveCapacityExceeded
        case 13: // PlaybackCapacityExceeded
            displayError('Server capacity limit reached. Please try again later.');
            break;

        default:
            displayError(`An error occurred: ${error.value}`);
            console.error('Error details:', error);
    }
});

function displayError(message) {
    const errorDiv = document.getElementById('errorDiv');
    errorDiv.textContent = message;
    errorDiv.style.display = 'block';
}

Monitoring connection status

In addition to error events, you can monitor the streaming connection status:

webPlayer.onStreamStatusChanged.register((status) => {
    console.log(`Connection status: ${status.state} - ${status.value}`);

    // Handle specific connection states
    if (status.state === 5) { // Streaming
        console.log('Successfully streaming');
    } else if (status.state === 31) { // UnauthorizedToken
        console.error('Token was denied - check user privileges');
    }
});

Refer to the StreamingConnectionStatus enum in the TypeScript definitions for a complete list of connection status codes.

Connection life cycle and recovery

Overview

The player must be connected to the Media Gateway to stream video. Various situations can prevent or interrupt streaming, and the GWP handles connection issues differently depending on whether they are recoverable.

Initial connection

When you call start(), the player establishes a connection to the Media Gateway. This method returns a Promise:

try {
    await webPlayer.start(cameraGuid, mediaGatewayEndpoint, getTokenFct);
    console.log('Player started successfully');
} catch (error) {
    console.error('Failed to start player:', error);
    // Possible causes: invalid parameters, network issues, invalid token
    // You can periodically retry if connectivity might be restored
}

Automatic reconnection

Once the player is successfully started, if any streaming problem occurs later, the player will automatically attempt to reconnect and recover to its previous state (for example, playing live video).

The onStreamStatusChanged event will fire with the value ConnectingToMediaGateway (status code -1) once a connection timeout occurs:

webPlayer.onStreamStatusChanged.register((status) => {
    if (status.state === -1) {
        console.log('Connection lost, attempting to reconnect...');
    } else if (status.state === 5) {
        console.log('Successfully streaming');
    }
});

Recoverable vs non-recoverable errors

Recoverable Errors: Most streaming problems are considered recoverable, and the player will automatically go back to a valid state when the issue is resolved:

  • Connection timeouts
  • Network interruptions
  • Temporary server issues
  • Camera temporarily offline

Non-Recoverable Errors: Some errors require you to manually restart the player (call stop(), then start() again):

Status Code Description Required Action
NotEnoughBandwidth 19 Bandwidth limit reached Stop and restart player when bandwidth is available
MediaRouterStreamNotFound 22 Media Router couldn't find stream Verify camera configuration, restart player
StreamUnreachable 25 No route found for stream Check network topology, restart player
UnauthorizedToken 31 Token was denied Verify user privileges and token, restart player

Example: handling non-recoverable errors:

webPlayer.onStreamStatusChanged.register((status) => {
    const nonRecoverableStates = [19, 22, 25, 31];

    if (nonRecoverableStates.includes(status.state)) {
        console.error('Non-recoverable error:', status.value);

        // Display error to user
        displayError(`Cannot stream: ${status.value}. Please try again.`);

        // Cleanup and prepare for restart
        webPlayer.stop();

        // Optionally: implement retry logic with delay
        setTimeout(() => {
            retryPlayerStart();
        }, 5000);
    }
});

Best practices

  1. Handle Initial Connection Failures: Always wrap start() in a try-catch block
  2. Monitor Connection Status: Register to onStreamStatusChanged to track connection health
  3. Provide User Feedback: Display meaningful messages during reconnection attempts
  4. Implement Retry Logic: For non-recoverable errors, consider implementing exponential backoff retry
  5. Avoid Automatic Retries on User Errors: Don't auto-retry if the error is due to insufficient privileges or invalid configuration

Advanced features

PTZ control: real-world use case

Consider a large retail store using PTZ cameras to monitor different sections. A user can program the PTZ to focus on high-traffic areas during peak hours and adjust manually when suspicious activity is detected:

// Move the camera to monitor entrance
const ptz = webPlayer.ptzControl;
ptz.goToPreset(1); // Preset 1 is configured for the main entrance

// Follow a suspicious individual
ptz.startPanTilt(30, -20); // Pan right and tilt down
setTimeout(() => ptz.stopPanTilt(), 5000); // Stop after 5 seconds

// Zoom in for a closer look
ptz.startZoom(50); // Slowly zoom in
setTimeout(() => ptz.stopZoom(), 3000); // Stop after 3 seconds

Timeline API: real-world use case

A security operator in a corporate setting may want to review past events, such as motion detection in restricted areas:

// Set a timeline range to view activity during the night shift
webPlayer.timelineProvider.setTimelineRange(new Date('2023-12-23T22:00:00Z'), new Date('2023-12-24T06:00:00Z'));

// Display bookmarks and motion detection events
webPlayer.timelineProvider.onTimelineContentUpdated.register(({ events }) => {
    events.forEach(event => {
        if (event.kind === 1) { // Bookmark
            console.log(`Bookmark: ${event.details} at ${event.time}`);
        } else if (event.kind === 0) { // Recording sequence
            console.log(`Motion detected: starts at ${event.time} for ${event.duration}s`);
        }
    });
});

PTZ control

The GWP supports Pan-Tilt-Zoom (PTZ) control for compatible cameras.

const ptz = webPlayer.ptzControl;
ptz.startPanTilt(50, 30);  // Start panning and tilting
ptz.stopPanTilt();          // Stop movement
ptz.startZoom(100);         // Zoom in
ptz.stopZoom();             // Stop zooming
ptz.goToPreset(1);          // Move to a preset position

Timeline API

The Timeline API allows you to query and display playback metadata, including recorded video sequences and user bookmarks. The API is designed for graphical timeline representations and focuses on a "range of interest" (the visible portion of the timeline).

Important Limitations:

  • Maximum range: 72 hours between start and end time
  • Recommended range: 24 hours or less for optimal performance
  • The API does not provide user actions (like adding bookmarks) - use the Web SDK or REST SDK for those operations

Setting Timeline Range:

You must set a range of interest before receiving timeline updates. The range can include future times for live updates:

// Set a 24-hour range
const startTime = new Date('2023-12-24T00:00:00Z');
const endTime = new Date('2023-12-25T00:00:00Z');
webPlayer.timelineProvider.setTimelineRange(startTime, endTime);

Important

Register your event handler BEFORE calling setTimelineRange() to avoid missing initial data.

Handling Timeline Updates:

The onTimelineContentUpdated event fires whenever the timeline content changes within your range of interest:

webPlayer.timelineProvider.onTimelineContentUpdated.register((event) => {
    console.log('Coverage:', event.coverageStart, 'to', event.coverageEnd);
    console.log('Events:', event.events);

    event.events.forEach((timelineEvent) => {
        if (timelineEvent.kind === 0) {
            // RecordingSequence
            console.log('Recording from', timelineEvent.time,
                       'duration:', timelineEvent.duration, 'seconds');
        } else if (timelineEvent.kind === 1) {
            // Bookmark
            console.log('Bookmark at', timelineEvent.time,
                       'details:', timelineEvent.details);
        }
    });
});

Timeline Event Structure:

interface TimelineContentEvent {
    coverageStart: Date;    // Start of updated range
    coverageEnd: Date;      // End of updated range
    events: TimelineEvent[]; // All events in coverage range
}

interface TimelineEvent {
    time: Date;                        // Event time or start time
    duration?: number;                 // Duration in seconds (for sequences)
    details?: string;                  // User-provided details (for bookmarks)
    kind: 0 | 1;                      // 0 = RecordingSequence, 1 = Bookmark
}

Understanding Coverage:

The coverageStart and coverageEnd define which part of the timeline was updated. This can be smaller than your range of interest - areas outside the coverage are considered untouched:

// Your range: 00:00 to 24:00
// Coverage received: 10:00 to 14:00
// Interpretation: Only data between 10:00-14:00 changed;
//                 data before 10:00 and after 14:00 remains unchanged

Handling Overlapping Sequences:

Sequences may overlap between updates. You must merge overlapping sequences to build the complete timeline:

function mergeSequences(existingSequences, newSequences) {
    // Merge logic: combine overlapping sequences
    // This is left as an exercise - implement based on your UI needs
    return mergedSequences;
}

Live Updates:

If the endTime is in the future, you'll periodically receive updates for new live recordings:

// Set range including future time for live updates
const now = new Date();
const future = new Date(now.getTime() + (60 * 60 * 1000)); // +1 hour
webPlayer.timelineProvider.setTimelineRange(now, future);

// You'll receive updates as new recordings become available

Timeline Dynamics:

Timeline content can change in real-time:

  • Sequences may get shorter, longer, or disappear
  • Archivers going offline/online affects sequence availability
  • Retention policies may delete old archives
  • Multiple sources (camera, auxiliary archivers) create overlapping sequences

The "Near-Live" Gap:

There's typically a small gap (a few seconds) between the last recorded sequence and "live" time. This is the time it takes for live frames to be written to the archiver and become available for playback. This gap is called the "near-live" period.

Digital zoom

The GWP supports digital zoom when available (check if webPlayer.digitalZoomControl is non-null). Digital zoom allows users to magnify specific regions of the video for detailed viewing.

Key Features:

  • Zoom factor from 1x (no zoom) to 20x maximum
  • Navigate around the zoomed image
  • Optional preview canvas showing the zoomed region
  • Can zoom into black bars when video aspect ratio doesn't match container

Basic Usage:

const zoom = webPlayer.digitalZoomControl;

if (zoom) {
    // Zoom to a specific point
    zoom.goTo(0.5, 0.5, 2);  // x, y (normalized 0-1), zoom factor

    // Zoom into the center of current view
    zoom.zoom(3);  // Zoom factor 3x

    // Move around at current zoom level
    zoom.move(0.2, -0.1);  // Move right and up (normalized -1 to 1)

    // Zoom with focus point (keeps point at same location)
    zoom.zoomWithFocus(0.3, 0.3, 5);  // x, y, zoom factor

    // Reset to full image
    zoom.stop();

    // Get current position
    console.log(`Position: (${zoom.X}, ${zoom.Y}), Zoom: ${zoom.Zoom}x`);
}

Digital Zoom Preview:

The optional preview canvas shows an overview of the full image with the zoomed region highlighted:

const preview = zoom.Preview;

// Enable/disable the preview
preview.Enabled = true;

// Access the preview canvas for customization
const canvas = preview.Canvas;
canvas.style.position = 'absolute';
canvas.style.top = '10px';
canvas.style.left = '10px';
canvas.style.border = '2px solid white';

Default User Interactions:

The GWP provides built-in mouse/touch interactions for convenience:

On Player Canvas:

  • Click and drag: Moves the zoomed view - the center follows the cursor position
  • Mouse wheel: Not implemented by default (you must implement this yourself if needed)

On Preview Canvas:

  • Click: Centers the zoomed view on the clicked point
  • Drag: Continuously updates the center as you drag

Customizing or Disabling Interactions:

You can override default interactions by intercepting JavaScript events during the capture phase:

// Example: Disable default drag behavior
divContainer.addEventListener('mousedown', (event) => {
    event.stopPropagation();  // Prevents GWP's default handler
    // Implement your custom behavior here
}, true);  // true = capture phase

Implementing Mouse Wheel Zoom:

The GWP doesn't handle mouse wheel by default. Here's a complete implementation:

const zoom = webPlayer.digitalZoomControl;

divContainer.addEventListener('wheel', (event) => {
    event.preventDefault();

    if (!zoom) return;

    const delta = event.deltaY > 0 ? -0.5 : 0.5;  // Scroll direction
    const newZoom = Math.max(1, Math.min(20, zoom.Zoom + delta));

    zoom.zoom(newZoom);
}, { passive: false });

Taking Snapshots of Zoomed View:

// Snapshot of the zoomed portion only
const imageData = zoom.snapshot();
if (imageData) {
    // Convert to downloadable image
    const canvas = document.createElement('canvas');
    canvas.width = imageData.width;
    canvas.height = imageData.height;
    const ctx = canvas.getContext('2d');
    ctx.putImageData(imageData, 0, 0);

    const link = document.createElement('a');
    link.download = 'zoomed-snapshot.png';
    link.href = canvas.toDataURL();
    link.click();
}

Fisheye dewarping

When a fisheye lens is configured for a camera in Security Center, the GWP can dewarp the image to simulate a PTZ camera experience. This feature is available when Media Gateway provides dewarper configuration for the camera and webPlayer.dewarperControl is non-null.

Important Notes:

  • Dewarping is performed in the browser and can be resource-intensive
  • Availability depends on the camera's lens configuration in Security Center
  • webPlayer.dewarperControl is null when dewarping is not available for the current camera or session
  • Replaces digital zoom when available

Basic Usage:

const dewarper = webPlayer.dewarperControl;

if (dewarper) {
    // Check if currently dewarping
    console.log('Is dewarping:', dewarper.isDewarping);

    // Navigate using pan/tilt (in degrees)
    dewarper.gotoPanTilt(45, -20);  // Pan 45° right, tilt 20° down

    // Navigate using X/Y coordinates (normalized -1 to 1)
    dewarper.gotoXY(0.3, 0.3);  // Move to upper-right quadrant

    // Zoom (1x to 20x)
    dewarper.gotoZoom(3);  // 3x zoom

    // Get current position
    console.log(`Pan: ${dewarper.PanDegrees}°, Tilt: ${dewarper.TiltDegrees}°`);
    console.log(`Position: (${dewarper.X}, ${dewarper.Y}), Zoom: ${dewarper.ZoomFactor}x`);

    // Stop dewarping and return to original warped image
    dewarper.stopDewarping();
}

Dewarping Preview:

The preview shows the full fisheye image with the dewarped region highlighted. By default, it appears in the upper-left corner:

const preview = dewarper.Preview;

// Enable/disable preview
preview.Enabled = true;

// Access and customize the preview canvas
const canvas = preview.Canvas;

// Position and style the preview
canvas.style.position = 'absolute';
canvas.style.top = '10px';
canvas.style.left = '10px';
canvas.style.width = '200px';
canvas.style.height = '200px';

// Customize colors using CSS properties
canvas.style.color = 'rgba(255, 255, 0, 0.3)';      // Yellow tint inside visible zone
canvas.style.borderColor = 'red';                    // Red border around visible zone

CSS Customization Table:

CSS Property Effect
color (on preview canvas) Color/tint inside the visible dewarped zone
border-color (on preview canvas) Color of the border outlining the visible zone
color (on main dewarper canvas) Background color outside the fisheye circle

Default User Interactions:

The dewarper provides built-in mouse interactions for both preview and main canvas:

On the preview canvas:

  • Mouse wheel up: Increases zoom by 0.5x (up to maximum of 20x).
  • Mouse wheel down: Decreases zoom by 0.5x (down to minimum of 1x). Reducing zoom to 1.0x automatically calls stopDewarping() and returns to the original warped stream.
  • Left-click: Calls gotoXY() to center the dewarped view at the clicked point.
  • Click and drag: Continuously updates center position. The dewarped view follows the cursor.

On the main dewarped video canvas:

  • Mouse wheel: Zoom in/out (same behavior as preview).
  • Click and drag: Simulates gotoPanTilt(). Horizontal movement sets pan degrees, vertical movement sets tilt degrees.

Overriding default behaviors:

All default interactions can be overridden by intercepting events during the capture phase:

// Example: Disable zoom on mouse wheel
divContainer.addEventListener('wheel', (event) => {
    event.stopPropagation();  // Prevents GWP's default zoom behavior
    // Implement custom behavior or do nothing
}, true);  // true = capture phase

Snapshot

Capture still images from the video stream using the getSnapshot() method. This returns an ImageData object containing the last displayed frame, or null if no frame is available.

Basic Snapshot:

// Get snapshot from main player (includes watermarking, no zoom/dewarping)
const imageData = webPlayer.getSnapshot();

if (imageData) {
    // Convert ImageData to downloadable image
    const canvas = document.createElement('canvas');
    canvas.width = imageData.width;
    canvas.height = imageData.height;
    const ctx = canvas.getContext('2d');
    ctx.putImageData(imageData, 0, 0);

    // Download as PNG
    const link = document.createElement('a');
    link.download = `snapshot-${new Date().toISOString()}.png`;
    link.href = canvas.toDataURL('image/png');
    link.click();
}

Snapshot Comparison:

Different snapshot sources include different elements:

Source Includes Watermark Includes Zoom/Dewarping
webPlayer.getSnapshot() Yes No
digitalZoomControl.snapshot() No Yes (zoomed view only)
dewarperControl.snapshot() No Yes (dewarped view only)

Display Snapshot in Page:

function displaySnapshot(imageData) {
    const canvas = document.createElement('canvas');
    canvas.width = imageData.width;
    canvas.height = imageData.height;
    const ctx = canvas.getContext('2d');
    ctx.putImageData(imageData, 0, 0);

    const img = new Image();
    img.src = canvas.toDataURL();
    img.style.maxWidth = '300px';
    document.getElementById('snapshotContainer').appendChild(img);
}

// Take and display snapshot
const snapshot = webPlayer.getSnapshot();
if (snapshot) {
    displaySnapshot(snapshot);
}

Privacy protection

Toggle privacy protection on the video stream to mask sensitive content. When enabled, video will be obscured based on Security Center privacy settings.

// Toggle privacy protection on/off
webPlayer.togglePrivacy();

// Check current privacy protection state
console.log('Privacy protected:', webPlayer.isPrivacyProtected);

// Monitor privacy protection changes
webPlayer.onPrivacyProtectionChanged.register(() => {
    console.log('Privacy protection changed to:', webPlayer.isPrivacyProtected);

    // Update UI to reflect state
    if (webPlayer.isPrivacyProtected) {
        console.log('Video is now privacy protected');
    } else {
        console.log('Video is now unprotected');
    }
});

Note

Privacy protection availability depends on camera configuration and user privileges in Security Center.

Audio playback

The GWP supports audio streaming when the camera provides an AAC audio codec stream.

Requirements:

  • Codec: Only AAC audio is currently supported
  • Live Audio: Camera must have a microphone
  • Playback Audio: "Audio recording" must be enabled in the camera configuration (disabled by default in Security Center)
  • User Privileges: User must have appropriate audio viewing privileges

Checking Audio Availability:

// Check if audio is available for this camera
console.log('Audio available:', webPlayer.isAudioAvailable);

// Monitor audio availability changes
webPlayer.onAudioAvailabilityChanged.register((event) => {
    console.log('Audio availability changed:', event.isAudioAvailable);

    if (event.isAudioAvailable) {
        console.log('Audio is now available - you can enable it');
    } else {
        console.log('Audio is not available at this time');
    }
});

Note

isAudioAvailable checks camera capabilities and user privileges, but it doesn't guarantee audio is present at the current moment.

Enabling Audio Playback:

// Enable audio playback
webPlayer.setAudioEnabled(true);

// Disable audio
webPlayer.setAudioEnabled(false);

// Check if audio is currently enabled
console.log('Audio enabled:', webPlayer.isAudioEnabled);

// Monitor audio state changes
webPlayer.onAudioStateChanged.register((event) => {
    console.log('Audio state changed:', event.isAudioEnabled);

    // Update UI (for example, toggle mute button)
    updateMuteButton(event.isAudioEnabled);
});

Important

Modern browsers prevent audio from playing automatically without user interaction. If you try to enable audio on page load or without a user action, the browser will likely block it.

Best practices:

  1. Only enable audio in response to user actions (button click, touch event, and so on).
  2. Never auto-enable audio on page load or player start.
  3. Provide UI controls for users to explicitly enable or disable audio.

Example: audio toggle button:

// HTML: <button id="toggleAudioBtn">Unmute</button>

const audioBtn = document.getElementById('toggleAudioBtn');

audioBtn.addEventListener('click', () => {
    // User action triggers audio - browser allows this
    const currentState = webPlayer.isAudioEnabled;
    webPlayer.setAudioEnabled(!currentState);

    // Update button text
    audioBtn.textContent = !currentState ? 'Mute' : 'Unmute';
});

// Keep button in sync with audio state
webPlayer.onAudioStateChanged.register((event) => {
    audioBtn.textContent = event.isAudioEnabled ? 'Mute' : 'Unmute';
});

Browser Autoplay Consequences:

If you attempt to enable audio without user interaction:

  • The browser may blacklist your page from playing audio
  • Future audio enable attempts may also be blocked
  • Users may need to manually adjust browser permissions to restore audio

Handling Autoplay Failures:

There's no direct event for autoplay blocking. If audio doesn't play after enabling it, assume the browser blocked it and prompt the user to click an audio button.

Stream usage and resolution selection

In Security Center, cameras can provide multiple stream configurations labeled by "stream usage":

  1. Live - Default live viewing stream
  2. Recording - Stream being recorded to archiver
  3. Remote - Optimized for remote/WAN viewing
  4. Low Resolution - Lower quality for bandwidth savings
  5. High Resolution - Highest quality available

Automatic Stream Selection:

When Media Gateway uses automatic stream selection in live mode, it sends the configured thresholds to GWP. GWP then chooses the stream based on player size:

// Automatic mode with the default Media Gateway thresholds
// - Player size < 640x480: Uses Low Resolution stream
// - Player size 640x480 to 1280x720: Uses Live stream
// - Player size > 1280x720: Uses High Resolution stream

// The stream automatically switches when the player is resized

Configuration:

Stream selection is configured in the Media Gateway configuration page in Config Tool. You can choose:

  • Specific stream usage (for example, always use High Resolution)
  • Automatic mode with custom thresholds

Transcoding:

If the browser doesn't support the camera's codec, the Media Gateway can transcode the stream. Transcoding configuration in Media Gateway settings:

  • Never - No transcoding (some streams may be unplayable)
  • For PTZ Only - Transcode only when PTZ mode is enabled
  • Always - Allow transcoding for unsupported codecs

PTZ Low-Latency Mode:

Enable PTZ mode to prioritize low latency over stream quality (may trigger transcoding):

// Enable PTZ mode for low-latency control
webPlayer.setPtzMode(true);

// Perform PTZ operations with reduced latency
const ptz = webPlayer.ptzControl;
ptz.startPanTilt(50, 0);

// Disable when done to reduce server load
webPlayer.setPtzMode(false);

Note

Transcoding is computationally expensive for the Media Gateway server. Configure maximum output resolution and frame rate limits in Media Gateway settings to control resource usage.

Diagnostic overlay

The GWP includes a built-in diagnostic overlay for troubleshooting stream issues. The overlay displays real-time information about the stream, including codec, resolution, frame rate, latency, and connection state.

Enable/Disable the Overlay:

// Show the diagnostic overlay
webPlayer.showDebugOverlay(true);

// Hide the diagnostic overlay
webPlayer.showDebugOverlay(false);

// Toggle with keyboard shortcut: Ctrl+Shift+A (when player canvas has focus)

Overlay Information Includes:

  • Tile ID and camera information
  • Video codec and resolution
  • Frame rate (current and average)
  • Player state and streaming state
  • Network latency (global and local)
  • Media time and timestamps
  • Bitrate and key frame interval

Important

The diagnostic overlay's appearance and content may change in future versions. It is intended for troubleshooting only, not for production use.

Enable GWP Console Logs:

For detailed debugging information in the browser console:

// Enable standard GWP logs (Info level)
gwp.enableLogs();

// Enable verbose/intense logging (Debug level - very detailed)
gwp.enableLogs(true);

// Disable logs (warnings and errors still shown)
gwp.disableLogs();

Log Filtering: All GWP logs are prefixed with the 🐹 emoji for easy filtering in the browser console.

Browser-Specific Behavior:

  • Chrome: GWP logs appear as "Info" level
  • Firefox: GWP logs appear as "Logs" and "Info" levels

Warning

Intense logging (gwp.enableLogs(true)) generates a large volume of output and can impact performance. Use it only when necessary for troubleshooting, and disable it when done.

Advanced: multiplexing multiple players

By default, each player creates its own WebSocket connection to the Media Gateway. If you need to display many players simultaneously, you can multiplex them over a single WebSocket connection for better performance and resource efficiency.

Note

This is an advanced feature. A communication failure of the shared socket will impact all players using it.

Creating a Media Gateway service

First, create a shared Media Gateway service:

const mediaGatewayService = await gwp.buildMediaGatewayService(
    mediaGatewayEndpoint,
    getTokenFct
);

Starting players with the service

Use startWithService() instead of start() for each player:

// Create multiple players
const player1 = gwp.buildPlayer(document.getElementById('player1'));
const player2 = gwp.buildPlayer(document.getElementById('player2'));
const player3 = gwp.buildPlayer(document.getElementById('player3'));

// Start all players with the same service
await player1.startWithService(camera1Guid, mediaGatewayService);
await player2.startWithService(camera2Guid, mediaGatewayService);
await player3.startWithService(camera3Guid, mediaGatewayService);

// Control each player independently
player1.playLive();
player2.playLive();
player3.seek(new Date('2023-12-24T10:00:00Z'));

Complete example

async function setupMultiplePlayers() {
    try {
        // Create shared service
        const mediaGatewayService = await gwp.buildMediaGatewayService(
            'https://gateway.example.com/media',
            getTokenFct
        );

        // Define cameras to display
        const cameras = [
            { id: 'camera-guid-1', container: 'player1' },
            { id: 'camera-guid-2', container: 'player2' },
            { id: 'camera-guid-3', container: 'player3' },
            { id: 'camera-guid-4', container: 'player4' }
        ];

        // Create and start all players
        const players = [];
        for (const cam of cameras) {
            const player = gwp.buildPlayer(document.getElementById(cam.container));

            // Register error handler
            player.onErrorStateRaised.register((error) => {
                console.error(`Player ${cam.container} error:`, error.value);
            });

            await player.startWithService(cam.id, mediaGatewayService);
            player.playLive();

            players.push(player);
        }

        console.log(`Started ${players.length} players over single WebSocket`);

        return players;
    } catch (error) {
        console.error('Failed to setup multiplexed players:', error);
        throw error;
    }
}

Benefits and considerations

Benefits:

  • Reduced number of WebSocket connections
  • Lower network overhead
  • Better resource utilization
  • Improved performance with many simultaneous players

Considerations:

  • Single point of failure: if the shared WebSocket connection fails, all players are affected
  • More complex error handling
  • Players must connect to the same Media Gateway agent

Limitations

  1. Audio: Only AAC audio codec is supported. For playback, "audio recording" must be enabled in the camera configuration (disabled by default in Security Center).
  2. Reverse Playback: Smooth reverse playback is only supported for MJPEG streams. Other codecs will play keyframes only during reverse playback (recommended minimum speed: -6x).
  3. Browser Codec Support: Some codecs may require transcoding on the Media Gateway server. Currently, most browsers support H.264 and MJPEG decoding natively.
  4. Dewarping availability: Dewarping is available only when Media Gateway provides dewarper configuration for the camera and webPlayer.dewarperControl is non-null.
  5. Dewarping performance: Dewarping is performed in the browser and can be resource-intensive. Test performance with the browsers and camera configurations that your application supports.
  6. CORS Configuration: Media Gateway includes CORS handling for GWP endpoints. Configure origin restrictions only when your deployment requires an explicit origin policy. See the CORS Configuration section.

Cross-origin resource sharing (CORS)

Overview

Cross-Origin Resource Sharing (CORS) is a security mechanism enforced by web browsers that restricts how resources on a web server can be requested from a different origin. Media Gateway includes CORS handling for GWP endpoints such as /v2/token, /v2/files, and /v2/ws. Use the CORS configuration only when your deployment needs to restrict or explicitly allow origins.

Configuring CORS restrictions

To enforce CORS restrictions beyond the default GWP endpoint handling, administrators can modify the MediaGateway.gconfig file. This file is located in the ConfigurationFiles directory on the Media Gateway server. If the file does not exist, create it manually in this directory.

Location of the ConfigurationFiles directory

Typically, the ConfigurationFiles directory is found in:

C:\Program Files (x86)\Genetec Security Center X.X\

where X.X represents the version of Security Center installed on the server.

Restricting access to specific domains

To limit CORS access exclusively to specific domains, create or modify the MediaGateway.gconfig file and include the following XML structure:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <MediaGateway EnforceStrictCrossOrigin="true"/>
</Configuration>

This setting prevents other web applications from making requests to the Media Gateway, allowing only official Security Center clients to access it.

Defining a custom allowed-origins list

For deployments that require an explicit origin allowlist, administrators can specify allowed origins. To define specific origins, update the MediaGateway.gconfig file as follows:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <MediaGateway EnforceStrictCrossOrigin="true">
        <AllowedOrigin Origin="https://example1.com" />
        <AllowedOrigin Origin="https://example2.com" />
        <AllowedOrigin Origin="https://web.example3.com" />
    </MediaGateway>
</Configuration>

In this configuration, the configured origin policy allows only the domains example1.com, example2.com, and web.example3.com.

Troubleshooting

This section covers common issues and their solutions when working with the Genetec Web Player.

Most common issues

The following are the most frequently encountered issues by developers:

Browser blocks untrusted certificate (self-signed certificate)

Symptoms:

  • Browser shows security warning or blocks connection
  • "Your connection is not private" or "NET::ERR_CERT_AUTHORITY_INVALID" error
  • Unable to load gwp.js or connect to Media Gateway
  • Console shows certificate errors

Cause: The Media Gateway is using a self-signed SSL certificate that the browser doesn't trust.

Solutions:

  1. Accept the Certificate in Browser (Development/Testing Only)

    • Navigate directly to the Media Gateway URL in your browser: https://<MediaGatewayAddress>
    • Browser will show security warning
    • Click "Advanced" and "Proceed to [site]" (or similar option depending on browser)
    • This adds a temporary exception for the certificate. This only works for testing and must be done in each browser/device
  2. Install Valid SSL Certificate (Recommended for Production)

    • Obtain an SSL certificate from a trusted Certificate Authority (CA)
    • Install the certificate on the Media Gateway server
    • Configure Media Gateway to use the valid certificate
    • This is the recommended approach for production environments
  3. Install Self-Signed Certificate in Operating System (Development)

    • Export the self-signed certificate from the Media Gateway
    • Install it in the operating system's trusted root certificate store
    • Restart browser after installation
    • More permanent than browser exceptions but still not recommended for production

Important

Self-signed certificates should only be used in development/testing environments. Production environments should always use certificates from trusted Certificate Authorities.

401 Unauthorized: invalid credentials, privileges, or access rights

Symptoms:

  • HTTP 401 Unauthorized error when retrieving token
  • Error code 16 (InsufficientPrivilege)
  • Video player fails to start or shows permission error
  • "Access denied" messages

Cause: Token retrieval failed. For HTTP 401 responses, Media Gateway returns the authentication result in the response body. Use that value to choose the next check instead of relying only on the HTTP status text.

Common 401 response bodies:

Response body What to check
BadCredentials Verify the user name, password, and Basic <Base64(username;sdkCertificate:password)> header format.
InsufficientPrivileges Verify the user has Live hit monitoring and at least one of View live video or View playback on the requested camera.
MissingSdkCertificate Add the SDK certificate to the user name part of the Basic credential string: username;sdkCertificate.
InvalidSdkCertificate Verify that the SDK certificate string matches the Security Center license.
MissingMediaSdkLicense Verify that the Security Center system has a Media SDK license.
Unknown Verify that the request includes a supported authentication header.

Solutions:

A. Check credentials

  1. Verify username and password are correct.
  2. Verify SDK certificate string is correct.
  3. Check Authorization header format: Basic <Base64(username;sdkCertificate:password)>.
  4. Ensure no extra spaces or special characters in credentials.
  5. Test login in Security Center Config Tool to confirm credentials work.

B. Check Security Center privileges

Required access for GWP camera streaming:

  1. A valid Security Center user name and password, or another supported authentication method.
  2. A valid SDK certificate.
  3. A Security Center system with a Media SDK license.
  4. "Live hit monitoring" (Web App privileges).
  5. At least one of "View live video" or "View playback" on the requested camera.

Additional privileges depending on features used:

  1. For PTZ: Check PTZ motor privileges (requires "View live video" first).

See the complete Security Center privileges section for details.

C. Check partition access rights

  1. Verify the user has access rights to the partition containing the camera.
  2. In Security Center Config Tool:
    • Go to User Management.
    • Select the user.
    • Check "Access rights" tab.
    • Ensure the user has access to the camera's partition.
  3. Common mistake: User has all privileges but no partition access.

D. Check camera configuration

  1. Verify the camera GUID is correct.
  2. Ensure the camera exists and is online in Security Center.
  3. Check that the camera is assigned to a partition the user can access.

Testing steps:

// Test token retrieval
const testToken = async () => {
    try {
        const response = await fetch(`${mediaGatewayEndpoint}/v2/token/${cameraId}`, {
            credentials: 'include',
            headers: {
                'Authorization': `Basic ${btoa(username + ";" + sdkCertificate + ":" + password)}`
            }
        });

        const responseText = await response.text();
        console.log('Status:', response.status);
        if (response.ok) {
            console.log('Token retrieved successfully');
        } else {
            console.error('Failed:', response.status, responseText || response.statusText);
        }
    } catch (error) {
        console.error('Error:', error);
    }
};

CORS (Cross-Origin Resource Sharing) errors

Symptoms:

  • Browser console shows CORS errors
  • "Access to fetch/XMLHttpRequest blocked by CORS policy" error
  • "No 'Access-Control-Allow-Origin' header is present"
  • Token retrieval or WebSocket connection fails

Cause: The browser is rejecting the cross-origin request. GWP endpoints are handled by Media Gateway CORS logic, so first verify the request URL and origin. If your deployment enforces an explicit origin policy, verify that the policy includes your web application's exact origin.

Solutions:

  1. Verify the GWP endpoint URL

    Make sure your application calls the GWP endpoints exposed by Media Gateway, such as /v2/token/{cameraId}, /v2/files/gwp.js, and /v2/ws.

  2. Configure Media Gateway CORS Settings, if your deployment requires an explicit origin policy

    Modify the MediaGateway.gconfig file located in the ConfigurationFiles directory:

    C:\Program Files (x86)\Genetec Security Center X.X\ConfigurationFiles\MediaGateway.gconfig
    

    Option A: Allow specific origins (Recommended)

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <MediaGateway EnforceStrictCrossOrigin="true">
            <AllowedOrigin Origin="https://yourapp.example.com" />
            <AllowedOrigin Origin="http://localhost:3000" />
        </MediaGateway>
    </Configuration>

    Option B: Allow all origins (Development only - NOT recommended for production)

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <MediaGateway EnforceStrictCrossOrigin="false"/>
    </Configuration>
  3. Restart the Media Gateway Role after modifying the configuration file

  4. Verify Your Application's Origin

    • Origin includes protocol, domain, and port
    • Examples: https://app.example.com, http://localhost:3000, https://192.168.1.100:8080
    • Make sure the exact origin is listed in the configuration
  5. Check for Multiple Origins

    • If testing from multiple locations (localhost, staging, production), add all origins

Common CORS Mistakes:

  • Calling a non-GWP endpoint by mistake
  • Forgetting to restart Media Gateway after config change
  • Origin mismatch (for example, http vs https, different port numbers)
  • Trailing slashes in origin URLs
  • Using IP address in code but domain name in CORS config (or vice versa)

See the complete CORS Configuration section for more details.

gwp.js source mismatch

Symptoms:

  • Unexpected errors or exceptions
  • Missing methods or properties
  • Features not working as documented
  • "undefined is not a function" errors
  • Inconsistent behavior

Cause: The browser is using a stale gwp.js file or a gwp.js file loaded from a different Media Gateway than the one used for token retrieval and streaming.

Solutions:

  1. Always Load from Media Gateway

    Correct approach:

    <script src="https://<MediaGatewayAddress>/media/v2/files/gwp.js"></script>

    Incorrect approaches:

    • Using a downloaded or cached copy from a different Security Center version
    • Hosting gwp.js on your own server
    • Loading from a different Media Gateway than you are connecting to
  2. Record the GWP Library Version

    // Check GWP version
    console.log('GWP Version:', gwp.version());
  3. Clear Browser Cache

    • Browser may be caching an old version of gwp.js
    • Hard refresh: Ctrl+F5 (Windows) or Cmd+Shift+R (Mac)
    • Clear browser cache completely
    • Try in incognito/private browsing mode
  4. Check for Multiple Script Tags

    • Ensure you're not loading gwp.js multiple times
    • Check that no other libraries are loading an older version
  5. After Security Center Upgrade

    • If Security Center was upgraded, the gwp.js file changes automatically
    • Users with cached versions will have mismatches
    • Consider cache-busting strategies:
      <script src="https://<MediaGatewayAddress>/media/v2/files/gwp.js?v=<cache-version>"></script>

Prevention:

  • Always reference gwp.js from the Media Gateway server
  • Don't download and host gwp.js separately
  • Document the GWP library version and Security Center version your application is tested with
  • Test thoroughly after Security Center upgrades

See the Installation section for more details.

Using browser developer tools

Enable GWP logs and use browser developer tools to diagnose issues:

// Enable detailed GWP logging
gwp.enableLogs(true);

Check the Browser Console:

  1. Open Developer Tools (F12)
  2. Go to Console tab
  3. Look for error messages, warnings, or GWP logs
  4. Note error codes and descriptions

Check Network Tab:

  1. Open Developer Tools (F12)
  2. Go to Network tab
  3. Filter for WebSocket connections (WS/WSS)
  4. Check for failed requests or CORS errors
  5. Verify token retrieval requests succeed

Check the Debug Overlay:

// Show diagnostic overlay on the player
webPlayer.showDebugOverlay(true);

The debug overlay displays real-time information about:

  • Connection status
  • Stream statistics
  • Frame rate and codec information
  • Buffering status

Getting additional help

If issues persist after trying the solutions above:

  1. Enable verbose logging:

    gwp.enableLogs(true); // Enable intense logging
  2. Gather diagnostic information:

    • GWP version: gwp.version()
    • Security Center version
    • Browser and OS version
    • Error codes from console
    • Network tab screenshots showing failed requests
  3. Contact Genetec Support with the diagnostic information

Additional debugging tips

  • Use Logs: Enable GWP logs to gather detailed information:

    gwp.enableLogs();
  • Check Network Accessibility: Ensure the Media Gateway is reachable from your network.

  • Validate Configuration: Confirm the Media Gateway role and permissions are properly configured in Security Center.

See also

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Media Gateway

Genetec Web Player

Clone this wiki locally