Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Welcome to the BigBlueButton API PHP

This is the official PHP client library for the BigBlueButton API. It enables PHP applications to create meetings, manage users and recordings, and use all other integration endpoints of a BigBlueButton server.

In this documentation, we explain the installation and usage, checking out samples, setting up different configurations, and advanced settings of the library.

Library Objectives

  • Full API coverage: support all endpoints of the official BigBlueButton integration API across supported server versions (BBB 2.x, 3.x and 4.x), including new endpoints and parameters shortly after they appear in the server.
  • Zero runtime dependencies: besides PHP extensions (curl, json, mbstring, simplexml), the library ships without dependencies. It works out of the box with curl and can optionally use any injected PSR-18 http client (the PSR interfaces are a suggested installation).
  • Typed and self-documenting: every endpoint has a dedicated parameters and response class with typed getters, backed by enums for closed value sets (layouts, roles, policies, features).
  • Tested against real servers: unit tests run against captured fixtures, integration tests run the complete suite against live BigBlueButton servers — with both transports (curl and an injected PSR-18 client).
  • Backwards compatible: the library supports old server versions and avoids breaking consumer code; former members are kept as deprecated stubs where formats changed.
  • Quality gates: PHPStan (level 8), php-cs-fixer and PHPUnit must pass cleanly; the pre-commit hooks enforce them on every commit.

Getting Started

Requirements

The library itself has no runtime package dependencies. It sends requests with curl by default; alternatively you can inject any PSR-18 http client.

Installation

bigbluebutton-api-php can be installed via Composer CLI

composer require bigbluebutton/bigbluebutton-api-php

or by editing composer.json

{
    "require": {
        "bigbluebutton/bigbluebutton-api-php": "^3.0"
    }
}

Configuration

The library reads the connection settings from two environment variables:

BBB_SERVER_BASE_URL=https://your-bbb-server.example.com/bigbluebutton/
BBB_SECRET=your-secret

You get both from your BigBlueButton server with bbb-conf --secret (see Server Configuration). In Laravel, add them to your .env; in other frameworks use the mechanism your application provides.

Alternatively, pass both values explicitly to the constructor:

use BigBlueButton\BigBlueButton;

$bbb = new BigBlueButton('https://your-bbb-server.example.com/bigbluebutton/', 'your-secret');

First call

A simple usage example that creates a meeting:

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\CreateMeetingParameters;

$bbb                 = new BigBlueButton();
$createMeetingParams = new CreateMeetingParameters('bbb-meeting-uid-65', 'BigBlueButton API Meeting');
$response            = $bbb->createMeeting($createMeetingParams);

echo 'Created Meeting with ID: ' . $response->getMeetingId();

From here, continue with the Meetings chapter and the Full Usage Sample.

HTTP Client

By default, this library sends all requests with PHP’s curl extension — no HTTP client package is required:

use BigBlueButton\BigBlueButton;

$bbb = new BigBlueButton('https://your-server.example.com/bigbluebutton/', 'your-secret');

Injecting a PSR-18 http client

Alternatively, you can inject any PSR-18 http client together with the PSR-17 request and stream factories. This makes the library independent of curl and lets you reuse the client, its configuration and its logging/middleware stack from your application:

use BigBlueButton\BigBlueButton;

$bbb = BigBlueButton::createWithHttpClient(
    $httpClient,        // Psr\Http\Client\ClientInterface
    $requestFactory,    // Psr\Http\Message\RequestFactoryInterface
    $streamFactory,     // Psr\Http\Message\StreamFactoryInterface
    'https://your-server.example.com/bigbluebutton/',
    'your-secret',
);

The library itself has no package requirements — the PSR interfaces (psr/http-client, psr/http-factory) are a suggested installation and ship with every common PSR-18 implementation anyway. Bring your own client.

Example: Guzzle

use BigBlueButton\BigBlueButton;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;

$client  = new Client(['timeout' => 10]);
$factory = new HttpFactory(); // implements all PSR-17 interfaces

$bbb = BigBlueButton::createWithHttpClient(
    $client,
    $factory,
    $factory,
    'https://your-server.example.com/bigbluebutton/',
    'your-secret',
);

Example: Symfony HttpClient

use BigBlueButton\BigBlueButton;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Component\HttpClient\HttplugClient;

$client  = new HttplugClient();       // PSR-18 compatible
$factory = new Psr17Factory();

$bbb = BigBlueButton::createWithHttpClient(
    $client,
    $factory,
    $factory,
    'https://your-server.example.com/bigbluebutton/',
    'your-secret',
);

Example: lightweight php-http/curl-client

use BigBlueButton\BigBlueButton;
use Http\Client\Curl\Client;
use Nyholm\Psr7\Factory\Psr17Factory;

$factory = new Psr17Factory();
$client  = new Client($factory, $factory, [
    CURLOPT_FOLLOWLOCATION => 1,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT        => 20,
]);

$bbb = BigBlueButton::createWithHttpClient(
    $client,
    $factory,
    $factory,
    'https://your-server.example.com/bigbluebutton/',
    'your-secret',
);

Behavior with an injected client

  • Timeouts and transport options are the responsibility of your client. setTimeOut() and setCurlOpts() have no effect on an instance created with createWithHttpClient(). Configure timeouts, SSL verification and proxies on the http client you pass in.
  • Redirects: the built-in curl transport follows redirects. If your client does not follow redirects by default, enable it if you rely on redirecting calls (e.g. join with redirect=true).
  • Multipart uploads (e.g. uploading a caption track via putRecordingTextTrack) are fully supported with an injected client — the library builds the multipart/form-data request itself.
  • Error handling stays the same: non-2xx responses throw a BadResponseException regardless of the transport used.

Cookies and the JSESSIONID

The BigBlueButton server sets a JSESSIONID cookie on some API interactions. This library does not maintain a cookie session — it captures exactly that one value and exposes it to the application.

What the library does

  • No cookie jar is kept between requests. Each API call is stateless; the library never sends cookies back to the server.
  • On every response, the JSESSIONID sent by the BBB-Server is read and validated (format checks; values containing path traversal, markup or script-like content are rejected).
  • A successfully captured session id is available to your application:
$bbb->joinMeeting($joinMeetingParams);

$sessionId = $bbb->getJSessionId();
  • You can also set it manually via setJSessionId() (e.g. to propagate an id captured elsewhere).

Transport specifics

Default curl transport

The curl transport uses a temporary cookie file per request to collect the cookies of the response. After the request, the file is read, the JSESSIONID is extracted and validated, and the temporary file is discarded. Nothing is persisted to disk beyond the lifetime of the request.

Injected PSR-18 http client

With createWithHttpClient(), the Set-Cookie headers of each response are inspected with the same validation as in the curl transport. The client itself may of course maintain its own cookie handling — that is outside the library’s scope.

What the library deliberately does not do

  • It does not store cookies across processes or requests.
  • It does not send the JSESSIONID (or any other cookie) back to the server.
  • It does not handle authentication cookies of your application — inject your own http client if you need full cookie middleware.

Meetings

In the BigBlueButton-world a video-conference is called a meeting. Once a meeting is created, it is a “ready-to-use” video-conference sitting on the BBB-Server and is waiting for people to join. A BBB-meeting is not something that would be created in advance (e.g. one week prior) in order to distribute a meeting-link inside an invitation to the participants.

Administration

Creating

One of the first steps is the creation of a meeting. A successfully created meeting is the prerequisite to enable participants (moderators and viewers) to join that meeting in a second step.

Default meeting

In order to create a new meeting, you only need to initiate a new object of the CreateMeetingParameters-class and pass an identifier ($meetingId) and a name ($meetingName) to the constructor. This parameter object ($createMeetingParameters) must now be passed to the createMeeting-function to launch the request to the BBB-Server. This function returns the BBB-server’s response ($createMeetingResponse).

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\CreateMeetingParameters;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// you can choose your own meeting number and title
$meetingId   = 123456;
$meetingName = "My first BBB-meeting";

// define the required parameters for the meeting
$createMeetingParameters = new CreateMeetingParameters($meetingId, $meetingName);

// launch the request to the BBB-Server and receive its response
$createMeetingResponse = $bbb->createMeeting($createMeetingParameters);

if (!$createMeetingResponse->success()) {
    throw new \Exception($createMeetingResponse->getMessage());
}

// steps once meeting has been created

Customized meeting

To adapt the predefined parameters of a meeting, the parameters for the creation of a meeting must be adapted before sending the creation-request to the BBB-Server. Please check the official API-Reference for all the possible settings.

// ...

$createMeetingParameters
    ->setWelcomeMessage('Dear Student, welcome to our lesson today!')
    ->setWebcamsOnlyForModerator(true)
    ;

// ...

Plugin metadata

BBB 3.0+ plugins can receive per-meeting configuration values through plugin_* create parameters. When the BBB-Server loads a plugin manifest (see pluginManifests / pluginManifestsFetchUrl), it replaces placeholders in the manifest with the matching values.

A manifest may for example contain:

{
    "name": "my-plugin",
    "settings": {
        "api-base-url": "${plugin_api-base-url:https://fallback.example.com}"
    }
}

When the meeting is created, ${plugin_api-base-url:...} is replaced by the value of the plugin_api-base-url parameter (or by the default after the : if the parameter is missing).

// ...

$createMeetingParameters
    ->addPluginMeta('api-base-url', 'https://my-server.example.com')  // sent as plugin_api-base-url
    ->addPluginMeta('vendor-name', 'Riadvice')
    ;

// several values at once
$createMeetingParameters->setPluginMeta([
    'api-base-url' => 'https://my-server.example.com',
    'vendor-name'  => 'Riadvice',
]);

// ...

The key is provided without the plugin_-prefix (a provided prefix is stripped). Note that the BBB-Server lowercases the parameter name, so lowercase keys should be preferred. Placeholders in the manifest must reference the lowercased name.

Shared notes (BBB 3.0)

The editor of the shared-notes area can be selected and pre-filled with initial content.

// ...

$createMeetingParameters
    ->setSharedNotesEditor('blockNote')                                   // 'etherpad' (default) or 'blockNote'
    ->setSharedNotesInitialContentJsonUrl('https://cdn.example.com/notes.json')  // initial content fetched by the client
    ->setSharedNotesInitialContentJson('{"type":"doc","content":[]}')    // ...or sent inline as POST module
    ;

// ...

The initial content can also be provided as raw Markdown (BBB 3.0.33+). The BlockNote JSON takes precedence over the Markdown; within the Markdown variants the URL is resolved first, then the inline parameter, then the POST module.

// ...

$createMeetingParameters
    ->setSharedNotesInitialContentMarkdownUrl('https://cdn.example.com/notes.md')  // fetched by the BBB-Server (HTTPS only)
    ->setSharedNotesInitialContentMarkdown('# Short notes')              // ...or inline as create parameter
    ->setSharedNotesInitialContentMarkdownModule('# Long notes...')      // ...or as POST module for large content
    ;

// ...

BBB 4.0 additions

// ...

$createMeetingParameters
    ->setLockSettingsPresenterPolicy(PresenterPolicy::FREE_FOR_ALL)      // 'Request to Present' policy: moderatorOnly | requireApproval (default) | freeForAll
    ->setNotifyRecordingAppend('This session is recorded for training.') // appended to the recording notification (requires notifyRecordingIsOn)
    ->setRequireUserConsentBeforeUnmuting(true)                          // consent dialog before moderators may unmute a user
    ;

// ...

Note that BBB 4.0 removed some parameters that are still supported by this library for older server versions: copyright and webVoice (create) and webVoiceConf (join) are obsolete, lockSettingsDisableNote (singular) is replaced by lockSettingsDisableNotes, and meetingLayout only accepts UNIFIED_LAYOUT (new default), CAMERAS_ONLY, PARTICIPANTS_AND_CHAT_ONLY, PRESENTATION_ONLY and MEDIA_ONLY anymore.

Client Settings Override

The BigBlueButton PHP API supports overriding HTML5 client settings from the settings.yml file. This feature allows you to customize the client behavior for specific meetings without modifying the server configuration.

Important

For security reasons, the client settings override feature is disabled by default. You must explicitly enable it by setting allowOverrideClientSettingsOnCreateCall=true.

Basic Usage
use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\CreateMeetingParameters;
use BigBlueButton\Core\ClientSettingsOverride;

// create an instance of the BBB-Client
$bbb = new BigBlueButton();

// define the required parameters for the meeting
$createMeetingParameters = new CreateMeetingParameters($meetingId, $meetingName);

// enable client settings override
$createMeetingParameters->setAllowOverrideClientSettingsOnCreateCall(true);

// create client settings override
$clientSettings = new ClientSettingsOverride([
    'public' => [
        'kurento' => [
            'wsUrl' => 'wss://test.bigbluebutton.org/bbb-webrtc-sfu'
        ],
        'media' => [
            'sipjsHackViaWs' => false
        ],
        'app' => [
            'appName' => 'Test Meeting',
            'helpLink' => 'https://www.bigbluebutton.org',
            'autoJoin' => false,
            'askForConfirmationOnLeave' => false,
            'userSettingsStorage' => 'localStorage',
            'defaultSettings' => [
                'application' => [
                    'overrideLocale' => 'en'
                ]
            ]
        ]
    ]
]);

// set the client settings override
$createMeetingParameters->setClientSettingsOverride($clientSettings);

// launch the request to the BBB-Server
$createMeetingResponse = $bbb->createMeeting($createMeetingParameters);
Advanced Usage with Individual Settings

You can also set individual settings using dot notation:

$clientSettings = new ClientSettingsOverride();

// set individual settings
$clientSettings->setSetting('public.app.appName', 'Custom Meeting Name');
$clientSettings->setSetting('public.kurento.wsUrl', 'wss://custom.example.com/sfu');
$clientSettings->setSetting('public.media.sipjsHackViaWs', false);

// get individual settings
$appName = $clientSettings->getSetting('public.app.appName');
$wsUrl = $clientSettings->getSetting('public.kurento.wsUrl', 'wss://default.example.com');

// remove settings
$clientSettings->removeSetting('public.media.sipjsHackViaWs');

// set the client settings override
$createMeetingParameters->setClientSettingsOverride($clientSettings);
Creating from JSON

You can create a ClientSettingsOverride object from a JSON string:

$jsonSettings = '{
    "public": {
        "app": {
            "appName": "JSON Meeting",
            "helpLink": "https://help.example.com"
        }
    }
}';

$clientSettings = ClientSettingsOverride::fromJson($jsonSettings);
$createMeetingParameters->setClientSettingsOverride($clientSettings);
Common Override Settings

Here are some commonly overridden settings:

Application Settings:

  • public.app.appName - Custom application name
  • public.app.helpLink - Custom help link
  • public.app.autoJoin - Auto-join meeting (true/false)
  • public.app.askForConfirmationOnLeave - Ask for confirmation when leaving
  • public.app.userSettingsStorage - Storage type for user settings

Kurento/WebRTC Settings:

  • public.kurento.wsUrl - Custom WebRTC SFU URL
  • public.kurento.turnUrl - Custom TURN server URL

Media Settings:

  • public.media.sipjsHackViaWs - SIP.js WebSocket hack
  • public.media.audio.codec - Preferred audio codec
  • public.media.video.codec - Preferred video codec

Theme Settings:

  • public.theme.branding.target - Custom branding target
  • public.theme.custom_css_url - Custom CSS URL

Note

The client settings override takes precedence over server configuration files. Use this feature carefully to avoid unexpected behavior.

Insert Document

Documents can be added either during the creation of a meeting (see $createMeetingParameters) or can be added once needed. This section is about adding documents into a running meeting.

old way (presentations)

Note

addPresentation() is deprecated — use the document-based API below instead.

use BigBlueButton\BigBlueButton;
use BigBlueButton\Enum\DocumentOption;
use BigBlueButton\Parameters\Config\DocumentOptions;
use BigBlueButton\Parameters\InsertDocumentParameters;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingId = 123456;
$url       = 'https://your.file.url/example.pdf';
$file      = __DIR__ . '/foldername/example.png';

// define the document options
$documentOptions = new DocumentOptions();
$documentOptions->addOption(DocumentOption::CURRENT, true);
$documentOptions->addOption(DocumentOption::REMOVABLE, false);
$documentOptions->addOption(DocumentOption::DOWNLOADABLE, true);

// announce 3 documents that shall to be added into the meeting
$insertDocumentParameters = new InsertDocumentParameters($meetingId);
$insertDocumentParameters
    ->addPresentation($url)                                      // by a URL (with default document options)
    ->addPresentation($url, null, null, $documentOptions)        // by a URL and defining the document options
    ->addPresentation($url, null, 'new_name.pdf')                // by a URL and rename the file
    ->addPresentation('filename.pdf', file_get_contents($file)); // by injecting a data stream and define the filename used on BBB-server

// launch the request to the BBB-Server and receive its response
$insertDocumentResponse = $bbb->insertDocument($insertDocumentParameters);

if (!$insertDocumentResponse->success()) {
    throw new \Exception($insertDocumentResponse->getMessage());
}

// steps once document has been added

new way (documents)

The document-based API replaces the deprecated addPresentation() calls. A document is either a DocumentUrl (referenced by URL) or a DocumentFile (read from the local filesystem); options like current, removable and downloadable are set directly on the document:

use BigBlueButton\Core\DocumentFile;
use BigBlueButton\Core\DocumentUrl;
use BigBlueButton\Parameters\InsertDocumentParameters;

// ...

$insertDocumentParameters = new InsertDocumentParameters($meetingId);

// by URL, marked as the current presentation
$insertDocumentParameters->addDocument(
    (new DocumentUrl('https://files.example.com/slides.pdf', 'slides.pdf'))->setCurrent(true)
);

// from the local filesystem, downloadable for the participants
$insertDocumentParameters->addDocument(
    (new DocumentFile('/path/to/handout.pdf', 'handout.pdf'))->setDownloadable(true)
);

$insertDocumentResponse = $bbb->insertDocument($insertDocumentParameters);

The same document objects are used when pre-uploading presentations into a meeting on create — see the DocumentableTrait methods on CreateMeetingParameters.

Joining

Once a meeting is created successfully, it is ready to let the participants into the meeting. This will be done with the join command. It needs to define into which meeting ($meetingId) and by what name ($name) the participant shall join the meeting. Additionally the role of the participant needs to be declared: either as moderator (Role::MODERATOR) or as a regular viewer (Role::VIEWER).

Important

The standard way to join a meeting is to redirect the user’s browser to a join URL, so that the BBB-Server can set the session cookie and forward the user to the html5 client:

$joinUrl = $bbb->getJoinMeetingURL($joinMeetingParameters);
header('Location: ' . $joinUrl);

Calling joinMeeting() server-side skips that cookie and typically requires allowRequestsWithoutSession=true on the meeting, which weakens the meeting’s security. Use it only for special cases where you explicitly need the join response (e.g. session tokens for API-driven clients).

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\JoinMeetingParameters;
use BigBlueButton\Enum\Role;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingID = 123456;
$name      = "Peter Parker";
$role1     = Role::MODERATOR;   // choose MODERATOR for a coordinating person
$role2     = Role::VIEWER;      // choose VIEWER for normal participants

// define the required parameters for the user to join the meeting
$joinMeetingParameters = new JoinMeetingParameters($meetingID, $name, $role1);
$joinMeetingParameters->setRedirect(true);  // will ensure that the user is redirected to the BBB-Server

// launch the request to the BBB-Server
$joinMeetingResponse = $bbb->joinMeeting($joinMeetingParameters);

if (!$joinMeetingResponse->success()) {
    throw new \Exception($joinMeetingResponse->getMessage());
}

$url = $joinMeetingResponse->getUrl();
// ...

In the example above, the user is redirected directly (setRedirect(true)) to the meeting on the BBB-Server. In case the user shall not be redirected (setRedirect(false)), the request will provide a URL in its response. This URL can be used to redirect the user later (e.g. by button or link).

Re-joining an existing user

BBB 3.0+ allows to create an additional session for an already joined user by providing the internal user id (existingUserID). All sessions of the user then appear as the same user in the user list. Optionally the original session can be invalidated (replaceSessionToken) and the new session can be named (sessionName) for easier identification. These are the same parameters used by the URLs returned from Get Join URL.

// ...

$joinMeetingParameters
    ->setExistingUserId('w_abc123def')            // internal user id of the joined user
    ->setSessionName('Mobile Device Transfer')    // optional: name the new session
    ->setReplaceSessionToken('st-orig-token')     // optional: invalidate the original session
    ;

// ...

Ending

A meeting can be ended (destroyed) by calling the endMeeting-command.


use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\EndMeetingParameters;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingID = 123456;

// define the required parameters to end a meeting
$endMeetingParameters = new EndMeetingParameters($meetingID);

// launch the request to the BBB-Server
$endMeetingResponse = $bbb->endMeeting($endMeetingParameters);

if (!$endMeetingResponse->success()) {
    throw new \Exception($endMeetingResponse->getMessage());
}

// ...

Monitoring

Is Meeting Running

This command will check if a meeting is currently running.

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\IsMeetingRunningParameters;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingID = 123456;

// define the required parameters for the user to join the meeting
$isMeetingRunningParameters = new IsMeetingRunningParameters($meetingID);

// launch the request to the BBB-Server
$isMeetingRunningResponse = $bbb->isMeetingRunning($isMeetingRunningParameters);

if (!$isMeetingRunningResponse->success()) {
    throw new \Exception($isMeetingRunningResponse->getMessage());
}

if (!$isMeetingRunningResponse->isRunning()) {
    // meeting is not running
} else {
    // meeting is running     
}

Warning

The BBB-server is understanding as a “running” meeting, where at least one participant has joint. This function deliver false if the meeting has been created only and no one has joint yet.

Is Meeting Existing

This command will check if a meeting is existing and just check if a meeting is available (successfully created) on the BBB-Server. In contrast with isRunning this command will not check if participants have been joined.

use BigBlueButton\BigBlueButton;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingID = 123456;

// launch the request to the BBB-Server
$isMeetingExisting = $bbb->isMeetingExisting($meetingID);

if (!$isMeetingExisting) {
    // meeting is not existing
} else {
    // meeting is existing     
}

Note

This function is a shortcut and runs getMeetingInfo-command under the hood. This is why its usage is a bit different compared to other interactions with the BBB-Server (e.g. no Parameter-Object needs to be used)

Get Meeting Info

This command will provide a lot of details of a meeting.

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetMeetingInfoParameters;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// define your variables
$meetingID = 123456;

// define the required parameters
$getMeetingInfoParameters = new GetMeetingInfoParameters($meetingID);

// launch the request to the BBB-Server
$getMeetingInfoResponse = $bbb->getMeetingInfo($getMeetingInfoParameters);

if (!$getMeetingInfoResponse->success()) {
    throw new \Exception($getMeetingInfoResponse->getMessage());
}

// get the meeting object
$meeting = $getMeetingInfoResponse->getMeeting();

// example of provided information
$meetingName = $meeting->getMeetingName();

Get Meetings

This command will provide a list of the existing meetings in the BBB-Server.

use BigBlueButton\BigBlueButton;

// create an instance of the BBB-Client (see details in the setup description)
$bbb = new BigBlueButton();

// launch the request to the BBB-Server
$getMeetingsResponse = $bbb->getMeetings();

if (!$getMeetingsResponse->success()) {
    throw new \Exception($getMeetingsResponse->getMessage());
}

// loop over all meetings
foreach ($getMeetingsResponse->getMeetings() as $meeting) {
    // treat meeting
}

Get Join URL

The getJoinUrl endpoint generates a new /join URL that can be used to create a new session for an existing user. By associating the new session token with the same user ID, all sessions will appear as the same user in the user list, ensuring accurate user counts.

Important

The sessionToken must belong to a connected HTML5 client session. A session token obtained from an API join (redirect=false) without a running client is rejected (e.g. "Meeting not found" on BBB 3.x).

This feature is particularly useful for:

  • Hybrid environments where multiple screens in the same room each require a distinct session with different layouts
  • Session transfers enabling seamless user session transfers to another device (e.g., mobile device scanning a QR code displayed on a computer)
  • Multi-device scenarios where a user wants to join the same meeting from multiple devices simultaneously

API Endpoint

GET http://yourserver.com/bigbluebutton/api/getJoinUrl?[parameters]

Parameters

ParameterTypeRequiredDescription
sessionTokenStringYesSession token to identify the user who is requesting a new join URL
replaceSessionBooleanNoWhen set to true, using the newly generated join URL will immediately invalidate the original session. Default: false
sessionNameStringNoAssign a descriptive name to the newly created session. Allows quick understanding of the session’s origin or purpose when reviewing user’s session history
enforceLayoutStringNoSpecify a layout enforcement setting for the new session. Overrides the enforceLayout parameter inherited from the original user’s session. If not specified, the new session inherits the layout behavior of the original session
userdata-*StringNoInclude additional user data parameters prefixed with userdata-. These parameters merge with the original user’s existing userdata settings. New session parameters take precedence over duplicates

Usage Examples

Basic Usage

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetJoinUrlParameters;

$bbb = new BigBlueButton();

// Get a new join URL for an existing session
$getJoinUrlParams = new GetJoinUrlParameters('existing-session-token-123');

$response = $bbb->getJoinUrl($getJoinUrlParams);

if ($response->success()) {
    $newJoinUrl = $response->getUrl();
    echo "New join URL: " . $newJoinUrl;
} else {
    echo "Error: " . $response->getMessage();
}

Advanced Usage with Session Replacement

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetJoinUrlParameters;
use BigBlueButton\Enum\MeetingLayout;

$bbb = new BigBlueButton();

// Create parameters with session replacement
$getJoinUrlParams = new GetJoinUrlParameters('mobile-session-token-456');

// Replace the original session when the new one is used
$getJoinUrlParams->setReplaceSession(true);

// Set a descriptive session name
$getJoinUrlParams->setSessionName('Mobile Device Transfer');

// Enforce a specific layout for the new session
$getJoinUrlParams->setEnforceLayout(MeetingLayout::VIDEO_FOCUS);

// Add custom userdata parameters
$getJoinUrlParams->addUserData('device-type', 'mobile');
$getJoinUrlParams->addUserData('transfer-source', 'desktop');
$getJoinUrlParams->addUserData('screen-size', 'small');

$response = $bbb->getJoinUrl($getJoinUrlParams);

if ($response->success()) {
    echo "New join URL: " . $response->getUrl();
    echo "Session Token: " . $response->getSessionToken();
    echo "Session Name: " . $response->getSessionName();
    echo "Replace Session: " . ($response->isReplaceSession() ? 'Yes' : 'No');
} else {
    echo "Error: " . $response->getMessage();
}

QR Code Generation for Session Transfer

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetJoinUrlParameters;

$bbb = new BigBlueButton();

// Generate a join URL for mobile device transfer
$getJoinUrlParams = new GetJoinUrlParameters('desktop-session-token-789');
$getJoinUrlParams->setSessionName('Mobile Transfer from Desktop');
$getJoinUrlParams->addUserData('transfer-initiated', date('Y-m-d H:i:s'));
$getJoinUrlParams->addUserData('device-platform', 'mobile');

$response = $bbb->getJoinUrl($getJoinUrlParams);

if ($response->success()) {
    $joinUrl = $response->getUrl();
    
    // Generate QR code (you'll need a QR code library)
    // $qrCode = generateQRCode($joinUrl);
    
    echo "Scan this QR code to transfer your session to mobile device:";
    echo "Join URL: " . $joinUrl;
} else {
    echo "Failed to generate transfer URL: " . $response->getMessage();
}

Multi-Screen Setup

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetJoinUrlParameters;
use BigBlueButton\Enum\MeetingLayout;

$bbb = new BigBlueButton();

// Original session token
$originalToken = 'main-screen-session-001';

// Create second screen with presentation focus
$secondScreenParams = new GetJoinUrlParameters($originalToken);
$secondScreenParams->setSessionName('Second Screen - Presentation View');
$secondScreenParams->setEnforceLayout(MeetingLayout::PRESENTATION_FOCUS);
$secondScreenParams->addUserData('screen-role', 'presentation');

$secondScreenResponse = $bbb->getJoinUrl($secondScreenParams);

// Create third screen with participant focus
$thirdScreenParams = new GetJoinUrlParameters($originalToken);
$thirdScreenParams->setSessionName('Third Screen - Participants View');
$thirdScreenParams->setEnforceLayout(MeetingLayout::PARTICIPANTS_CHAT_ONLY);
$thirdScreenParams->addUserData('screen-role', 'participants');

$thirdScreenResponse = $bbb->getJoinUrl($thirdScreenParams);

if ($secondScreenResponse->success() && $thirdScreenResponse->success()) {
    echo "Second Screen URL: " . $secondScreenResponse->getUrl();
    echo "Third Screen URL: " . $thirdScreenResponse->getUrl();
}

Response Fields

The response is JSON and provides the following fields:

FieldTypeDescription
urlStringThe generated join URL (including its checksum). Successful responses only
sessionTokenStringThe session token that was rejected. Failed responses only

Example of a successful response:

{
    "response": {
        "returncode": "SUCCESS",
        "message": "Join URL provided successfully.",
        "url": "https://yourserver.com/bigbluebutton/api/join?&redirect=true&existingUserID=w_t18rn7uc1wjm&role=MODERATOR&checksum=..."
    }
}

Response Handling

$response = $bbb->getJoinUrl($getJoinUrlParams);

if ($response->success()) {
    echo "Join URL: " . $response->getUrl();
} else {
    echo "Error: " . $response->getMessage();
    echo "Rejected session token: " . $response->getSessionToken();
}

Layout Options

The enforceLayout parameter accepts the same values as the meeting creation:

use BigBlueButton\Enum\MeetingLayout;

// Available layout options
MeetingLayout::UNIFIED_LAYOUT              // BBB 3.0+ (default in 4.0)
MeetingLayout::CAMERAS_ONLY
MeetingLayout::PARTICIPANTS_AND_CHAT_ONLY  // BBB 3.0+ (replaces PARTICIPANTS_CHAT_ONLY)
MeetingLayout::PRESENTATION_ONLY
MeetingLayout::PLUGINS_ONLY                // BBB 3.0+
MeetingLayout::MEDIA_ONLY

Warning

BBB 4.0 no longer accepts CUSTOM_LAYOUT, SMART_LAYOUT, PRESENTATION_FOCUS and VIDEO_FOCUS. The cases remain available in this library for BBB 2.x/3.x servers, but using them against a 4.0 server has no effect.

Userdata Parameters

Userdata parameters allow you to pass additional information about the session:

Common Userdata Parameters

ParameterExample ValueDescription
userdata-device-typemobile, desktop, tabletType of device
userdata-screen-rolemain, presentation, participantsScreen purpose in multi-screen setup
userdata-transfer-sourcedesktop, mobile, webSource device for session transfer
userdata-platformiOS, Android, Windows, macOSOperating system
userdata-app-version2.1.0Application version

Adding Userdata Parameters

// Single parameter
$getJoinUrlParams->addUserData('device-type', 'mobile');

// Multiple parameters
$getJoinUrlParams->addUserData('device-type', 'mobile');
$getJoinUrlParams->addUserData('platform', 'iOS');
$getJoinUrlParams->addUserData('app-version', '2.1.0');

// Complex data (JSON encoded)
$deviceInfo = [
    'type' => 'mobile',
    'os' => 'iOS',
    'version' => '15.0',
    'screen' => [
        'width' => 375,
        'height' => 667
    ]
];
$getJoinUrlParams->addUserData('device-info', json_encode($deviceInfo));

Security Considerations

Session Token Security

  • Session tokens are sensitive and should be handled securely
  • Only share session tokens with authorized users
  • Implement proper validation before generating new join URLs

Userdata Validation

  • Validate userdata parameters on both client and server side
  • Sanitize user input to prevent injection attacks
  • Consider implementing a blocklist for sensitive userdata parameters

Session Replacement

  • Use replaceSession=true carefully as it immediately invalidates the original session
  • Inform users when their original session will be replaced
  • Implement proper error handling for session replacement scenarios

Error Handling

Common error scenarios and their handling:

$response = $bbb->getJoinUrl($getJoinUrlParams);

if (!$response->success()) {
    $message = $response->getMessage();
    $statusCode = $response->getStatusCode();
    
    switch ($statusCode) {
        case '404':
            // Session token not found
            echo "Invalid or expired session token";
            break;
            
        case '403':
            // Access denied
            echo "Permission denied for session transfer";
            break;
            
        case '400':
            // Bad request
            echo "Invalid parameters provided";
            break;
            
        default:
            echo "Unknown error: " . $message;
    }
}

Best Practices

  1. Session Naming: Use descriptive session names to help users identify different sessions
  2. Layout Selection: Choose appropriate layouts for different device types and use cases
  3. Userdata Organization: Use consistent naming conventions for userdata parameters
  4. Error Handling: Implement comprehensive error handling for all scenarios
  5. Security: Validate and sanitize all input parameters
  6. User Experience: Provide clear feedback about session transfers and multi-screen setups

Use Case Examples

Education Scenario

A professor wants to display the main presentation on a projector while managing participants on a tablet:

// Main screen (projector) - presentation focus
$projectorParams = new GetJoinUrlParameters($professorSessionToken);
$projectorParams->setSessionName('Projector - Presentation View');
$projectorParams->setEnforceLayout(MeetingLayout::PRESENTATION_FOCUS);

// Tablet screen - participants management
$tabletParams = new GetJoinUrlParameters($professorSessionToken);
$tabletParams->setSessionName('Tablet - Participants Management');
$tabletParams->setEnforceLayout(MeetingLayout::PARTICIPANTS_CHAT_ONLY);

Corporate Scenario

An executive wants to transfer a meeting from desktop to mobile for commuting:

$transferParams = new GetJoinUrlParameters($desktopSessionToken);
$transferParams->setReplaceSession(true);
$transferParams->setSessionName('Mobile Transfer - ' . date('H:i'));
$transferParams->addUserData('transfer-reason', 'commute');
$transferParams->addUserData('connection-type', 'mobile');

Support Scenario

A support agent needs to join a customer meeting with elevated permissions:

$supportParams = new GetJoinUrlParameters($customerSessionToken);
$supportParams->setSessionName('Support Agent Session');
$supportParams->addUserData('role', 'support');
$supportParams->addUserData('support-id', $supportAgentId);
$supportParams->addUserData('elevated-permissions', 'true');

This API provides powerful flexibility for managing user sessions across different devices and scenarios while maintaining user identity and meeting continuity.

Learning Dashboard

The learningDashboard endpoint returns the Learning Analytics Dashboard data for the session’s meeting.

Access is restricted:

  • the session token must belong to a user with the MODERATOR role
  • the meeting must be running
  • the learningDashboard feature must not be listed in the meeting’s disabledFeatures

The data field of the response contains the dashboard’s JSON document serialized as a string.

Note

This endpoint is part of the client-facing API. A session token obtained through an API join (redirect=false) without a connected HTML5 client will be rejected with Invalid session token.

API Endpoint

GET http://yourserver.com/bigbluebutton/api/learningDashboard?[parameters]

Parameters

ParameterTypeRequiredDescription
sessionTokenStringYesSession token identifying the user requesting the dashboard data. Issued by /join and only known to the joined client

Usage Example

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\LearningDashboardParameters;

$bbb = new BigBlueButton();

$learningDashboardParams = new LearningDashboardParameters('xyn1fbqlrhug1j6z');

$response = $bbb->learningDashboard($learningDashboardParams);

if ($response->success()) {
    // the dashboard data is a JSON-encoded string
    $dashboardData = json_decode($response->getData(), true);

    foreach ($dashboardData['users'] as $userId => $user) {
        echo sprintf('%s (%s)', $user['name'], $user['role']) . PHP_EOL;
    }
} else {
    echo 'Error: ' . $response->getMessage();
}

Response Fields

FieldTypeDescription
dataStringThe learning dashboard data as a JSON-encoded string (successful responses only)
sessionTokenStringThe session token that was used for the request

Get Sessions

The getSessions endpoint returns all user sessions that currently exist on the BBB-Server. A session is created each time a user joins a meeting — even if the same user joins multiple times. Therefore the same meeting can appear multiple times in the result, once per session, distinguished by userName.

This is different from getMeetings, which returns one entry per meeting.

Typical use cases:

  • Monitoring active sessions: see which users currently hold a session token on the server
  • Session auditing: track multi-device or repeated joins of the same user
  • Debugging join flows: verify that generated join URLs actually created sessions

API Endpoint

GET http://yourserver.com/bigbluebutton/api/getSessions?checksum=<checksum>

The endpoint takes no parameters besides the checksum.

Usage Example

use BigBlueButton\BigBlueButton;

$bbb = new BigBlueButton();

$response = $bbb->getSessions();

if ($response->success()) {
    foreach ($response->getSessions() as $session) {
        echo sprintf(
            'Meeting: %s (%s) - User: %s',
            $session->getMeetingName(),
            $session->getMeetingId(),
            $session->getUserName()
        ) . PHP_EOL;
    }
} else {
    echo 'Error: ' . $response->getMessage();
}

Response Fields

Each session provides the following fields:

FieldTypeDescription
meetingIdStringThe internal meeting id of the meeting the session belongs to
meetingNameStringThe name of the meeting
userNameStringThe full name of the user that holds the session

If no sessions exist, the response contains the message key noSessions.

Remarks

  • Sessions created through an API join without a connected HTML5 client are removed by the server after a short period (about 2 minutes).
  • The meetingID in the response is the internal meeting id (as returned by CreateMeetingResponse::getInternalMeetingId()), not the external id used when creating the meeting.
  • Available on BBB 2.x, 3.x and 4.x servers.

Client Settings Override

The Client Settings Override feature allows you to customize the HTML5 client behavior for specific meetings by overriding settings from the server’s settings.yml file. This feature is available in BigBlueButton 3.0.0 and later.

Overview

Client settings override provides a way to:

  • Customize the application name and appearance
  • Configure WebRTC and media settings
  • Modify user interface behavior
  • Set custom themes and branding
  • Override locale and language settings

Important

For security reasons, this feature is disabled by default. You must explicitly enable it by setting allowOverrideClientSettingsOnCreateCall=true.

Variant via URL (BBB 3.0.25+)

Instead of passing the settings inline, you can reference a hosted JSON file. The URL variant takes precedence over the inline clientSettingsOverride payload and does not require allowOverrideClientSettingsOnCreateCall:

$createMeetingParameters->setClientSettingsOverrideJsonUrl('https://your-server.example.com/settings-override.json');

The BBB-Server fetches the JSON file when the meeting is created.

Core Classes

ClientSettingsOverride

The main class for handling client settings override.

use BigBlueButton\Core\ClientSettingsOverride;

Constructor

public function __construct(array $settings = [])

Creates a new ClientSettingsOverride instance with optional initial settings.

Parameters:

  • $settings (array) - Initial settings array

Methods

setSettings()
public function setSettings(array $settings): self

Sets all settings at once.

Parameters:

  • $settings (array) - The settings array
getSettings()
public function getSettings(): array

Returns all settings as an array.

setSetting()
public function setSetting(string $key, mixed $value): self

Sets a specific setting using dot notation.

Parameters:

  • $key (string) - The setting key (e.g., ‘public.app.appName’)
  • $value (mixed) - The setting value
getSetting()
public function getSetting(string $key, mixed $default = null): mixed

Gets a specific setting using dot notation.

Parameters:

  • $key (string) - The setting key
  • $default (mixed) - Default value if key doesn’t exist
removeSetting()
public function removeSetting(string $key): self

Removes a specific setting using dot notation.

Parameters:

  • $key (string) - The setting key to remove
toXML()
public function toXML(): string

Converts the settings to XML format for the BigBlueButton API request.

fromJson()
public static function fromJson(string $jsonString): self

Creates a ClientSettingsOverride instance from a JSON string.

Parameters:

  • $jsonString (string) - Valid JSON string containing settings

Throws:

  • \InvalidArgumentException if JSON is invalid

Integration with CreateMeetingParameters

The ClientSettingsOverride is used with the CreateMeetingParameters class:

setAllowOverrideClientSettingsOnCreateCall()

public function setAllowOverrideClientSettingsOnCreateCall(bool $allow): self

Enables or disables the client settings override feature.

setClientSettingsOverride()

public function setClientSettingsOverride(?ClientSettingsOverride $override): self

Sets the client settings override for the meeting.

getClientSettingsOverride()

public function getClientSettingsOverride(): ?ClientSettingsOverride

Returns the current client settings override.

Usage Examples

Basic Example

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\CreateMeetingParameters;
use BigBlueButton\Core\ClientSettingsOverride;

$bbb = new BigBlueButton();
$createParams = new CreateMeetingParameters('meeting123', 'Test Meeting');

// Enable client settings override
$createParams->setAllowOverrideClientSettingsOnCreateCall(true);

// Create settings override
$settings = new ClientSettingsOverride([
    'public' => [
        'app' => [
            'appName' => 'Custom Meeting Name',
            'helpLink' => 'https://help.example.com'
        ]
    ]
]);

// Apply settings
$createParams->setClientSettingsOverride($settings);

// Create meeting
$response = $bbb->createMeeting($createParams);

Advanced Configuration

$settings = new ClientSettingsOverride();

// Application settings
$settings->setSetting('public.app.appName', 'Enterprise Meeting');
$settings->setSetting('public.app.helpLink', 'https://support.company.com');
$settings->setSetting('public.app.autoJoin', false);
$settings->setSetting('public.app.askForConfirmationOnLeave', true);
$settings->setSetting('public.app.userSettingsStorage', 'localStorage');

// WebRTC settings
$settings->setSetting('public.kurento.wsUrl', 'wss://webrtc.company.com/sfu');
$settings->setSetting('public.kurento.turnUrl', 'turn:turn.company.com:443');

// Media settings
$settings->setSetting('public.media.sipjsHackViaWs', false);
$settings->setSetting('public.media.audio.codec', 'opus');
$settings->setSetting('public.media.video.codec', 'vp8');

// Theme settings
$settings->setSetting('public.theme.branding.target', '.branding-element');
$settings->setSetting('public.theme.custom_css_url', 'https://assets.company.com/theme.css');

// Locale settings
$settings->setSetting('public.defaultSettings.application.overrideLocale', 'fr');

$createParams->setClientSettingsOverride($settings);

JSON Configuration

$jsonConfig = '{
    "public": {
        "app": {
            "appName": "JSON Configured Meeting",
            "helpLink": "https://docs.example.com",
            "autoJoin": true
        },
        "kurento": {
            "wsUrl": "wss://webrtc.example.com/sfu"
        },
        "theme": {
            "branding": {
                "target": ".custom-branding"
            }
        }
    }
}';

$settings = ClientSettingsOverride::fromJson($jsonConfig);
$createParams->setClientSettingsOverride($settings);

Available Settings

Application Settings (public.app)

SettingTypeDescription
appNamestringCustom application name
helpLinkstringCustom help documentation URL
autoJoinbooleanAuto-join meeting when page loads
askForConfirmationOnLeavebooleanShow confirmation dialog when leaving
userSettingsStoragestringStorage type: ‘localStorage’, ‘sessionStorage’, ‘cookie’
displayBrandingAreabooleanShow/hide branding area

WebRTC Settings (public.kurento)

SettingTypeDescription
wsUrlstringCustom WebRTC SFU WebSocket URL
turnUrlstringCustom TURN server URL
turnUsernamestringTURN server username
turnCredentialstringTURN server credential

Media Settings (public.media)

SettingTypeDescription
sipjsHackViaWsbooleanEnable SIP.js WebSocket hack
audio.codecstringPreferred audio codec: ‘opus’, ‘pcmu’, ‘pcma’
video.codecstringPreferred video codec: ‘vp8’, ‘vp9’, ‘h264’
video.resolutionstringPreferred video resolution

Theme Settings (public.theme)

SettingTypeDescription
branding.targetstringCSS selector for branding elements
custom_css_urlstringURL to custom CSS file
logo.urlstringURL to custom logo image
favicon.urlstringURL to custom favicon

Default Settings (public.defaultSettings)

SettingTypeDescription
application.overrideLocalestringOverride locale (e.g., ‘en’, ‘fr’, ‘es’)
application.chat.enabledbooleanEnable/disable chat
application.poll.enabledbooleanEnable/disable polls

Security Considerations

  1. Enable Only When Needed: Only enable allowOverrideClientSettingsOnCreateCall when you actually need to override settings.

  2. Validate Input: Always validate user-provided settings before applying them.

  3. Sensitive Data: Avoid exposing sensitive configuration through client settings override.

  4. Network Security: Ensure custom WebSocket URLs are from trusted sources.

Error Handling

try {
    $settings = ClientSettingsOverride::fromJson($invalidJson);
} catch (\InvalidArgumentException $e) {
    // Handle invalid JSON
    error_log('Invalid JSON: ' . $e->getMessage());
    $settings = new ClientSettingsOverride(); // Fallback to empty settings
}

Best Practices

  1. Use Specific Settings: Only override the settings you actually need to change.

  2. Document Changes: Keep track of which settings you’re overriding for debugging purposes.

  3. Test Thoroughly: Test client settings override in a development environment before production use.

  4. Fallback Values: Provide sensible defaults when getting settings that might not exist.

  5. Performance: Avoid overly complex nested structures that might impact client performance.

Troubleshooting

Settings Not Applied

  • Verify allowOverrideClientSettingsOnCreateCall is set to true
  • Check that the settings structure matches the expected format
  • Ensure the BigBlueButton server version supports client settings override (3.0.0+)

Invalid JSON

  • Use try-catch blocks when calling fromJson()
  • Validate JSON structure before processing

WebSocket Connection Issues

  • Verify custom WebSocket URLs are accessible
  • Check firewall and network configuration
  • Ensure TURN server credentials are correct

Migration Notes

If you’re upgrading from an earlier version of BigBlueButton:

  1. Ensure your server is running BigBlueButton 3.0.0 or later
  2. Update your PHP API library to the latest version
  3. Review existing meeting creation code to add client settings override if needed
  4. Test thoroughly in a development environment

For more information about the available settings, refer to the official BigBlueButton documentation and your server’s settings.yml file.

Feedback

Warning

Experimental. The /api/feedback endpoint is reserved in the BBB server source but is not routed yet on current BBB releases — it returns HTTP 404 on BBB 3.x and 4.0-beta servers. This client implementation is provided in anticipation of the endpoint shipping in a future BBB release. Do not rely on it in production, and expect BadResponseException until your server actually provides the endpoint.

The feedback endpoint allows users to submit feedback about their meeting experience. This endpoint replaces the old /html5client/feedback endpoint with /api/feedback, providing a more standardized API approach for collecting user feedback.

This feature is particularly useful for:

  • User Experience Improvement - Collect structured feedback about meeting quality
  • Quality Assurance - Monitor user satisfaction and identify issues
  • Analytics - Gather data for improving the BigBlueButton platform
  • Support - Allow users to report problems or suggestions

API Endpoint

POST http://yourserver.com/bigbluebutton/api/feedback?[parameters]

Response Format: JSON (application/json)

Parameters

ParameterTypeRequiredDescription
sessionTokenStringYesSession token to identify the user who is submitting feedback
ratingIntegerNoNumeric rating for the meeting experience (typically 1-5)
commentStringNoTextual feedback or comments about the meeting experience
meetingIDStringNoMeeting ID for which the feedback is being submitted
userIDStringNoUser ID of the person submitting the feedback

Usage Examples

Basic Feedback Submission

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\FeedbackParameters;

$bbb = new BigBlueButton();

// Submit basic feedback with just a session token
$feedbackParams = new FeedbackParameters('user-session-token-123');

$response = $bbb->feedback($feedbackParams);

if ($response->success()) {
    echo "Feedback submitted successfully!";
    echo "Feedback ID: " . $response->getFeedbackID();
    echo "Status: " . $response->getStatus();
} else {
    echo "Error: " . $response->getMessage();
}

Complete Feedback Submission

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\FeedbackParameters;

$bbb = new BigBlueButton();

// Create comprehensive feedback
$feedbackParams = new FeedbackParameters('session-token-456');
$feedbackParams->setRating(4);
$feedbackParams->setComment('Great meeting overall! Audio quality was excellent, but video could be smoother.');
$feedbackParams->setMeetingID('weekly-team-meeting-001');
$feedbackParams->setUserID('participant-john-doe');

$response = $bbb->feedback($feedbackParams);

if ($response->success()) {
    echo "Feedback submitted successfully!";
    echo "Feedback ID: " . $response->getFeedbackID();
    echo "Submitted at: " . $response->getSubmittedAt();
    echo "Processed: " . ($response->getProcessed() ? 'Yes' : 'No');
} else {
    echo "Error: " . $response->getMessage();
    echo "Status Code: " . $response->getStatusCode();
}

Mobile App Feedback

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\FeedbackParameters;

$bbb = new BigBlueButton();

// Mobile app feedback with additional context
$feedbackParams = new FeedbackParameters('mobile-session-token-789');
$feedbackParams->setRating(5);
$feedbackParams->setComment('Excellent mobile experience! The app worked perfectly on my tablet.');
$feedbackParams->setMeetingID('mobile-presentation-123');
$feedbackParams->setUserID('mobile-user-456');

$response = $bbb->feedback($feedbackParams);

if ($response->success()) {
    // Store feedback ID for follow-up
    $feedbackId = $response->getFeedbackID();
    
    // Could also store additional metadata locally
    $feedbackData = [
        'feedback_id' => $feedbackId,
        'session_token' => $response->getSessionToken(),
        'rating' => $response->getRating(),
        'comment' => $response->getComment(),
        'submitted_at' => $response->getSubmittedAt()
    ];
    
    echo "Mobile feedback submitted with ID: " . $feedbackId;
}

Post-Meeting Feedback Collection

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\FeedbackParameters;

function collectMeetingFeedback($sessionToken, $meetingId, $userId) {
    $bbb = new BigBlueButton();
    
    // Create feedback parameters
    $feedbackParams = new FeedbackParameters($sessionToken);
    $feedbackParams->setMeetingID($meetingId);
    $feedbackParams->setUserID($userId);
    
    // In a real application, you would collect rating and comment from user input
    $rating = $_POST['rating'] ?? null; // 1-5 star rating
    $comment = $_POST['comment'] ?? ''; // User comments
    
    if ($rating !== null) {
        $feedbackParams->setRating((int)$rating);
    }
    
    if (!empty($comment)) {
        $feedbackParams->setComment($comment);
    }
    
    // Submit feedback
    $response = $bbb->feedback($feedbackParams);
    
    return $response;
}

// Usage after meeting ends
$sessionToken = 'user-session-from-meeting';
$meetingId = 'meeting-that-just-ended';
$userId = 'user-who-attended';

$feedbackResponse = collectMeetingFeedback($sessionToken, $meetingId, $userId);

if ($feedbackResponse->success()) {
    echo "Thank you for your feedback!";
} else {
    echo "Unable to submit feedback: " . $feedbackResponse->getMessage();
}

Batch Feedback Collection

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\FeedbackParameters;

$bbb = new BigBlueButton();

// Collect feedback from multiple users
$sessionTokens = [
    'user1-session-token',
    'user2-session-token',
    'user3-session-token'
];

$feedbackResults = [];

foreach ($sessionTokens as $sessionToken) {
    $feedbackParams = new FeedbackParameters($sessionToken);
    $feedbackParams->setRating(rand(3, 5)); // Simulate different ratings
    $feedbackParams->setComment('Automated feedback collection');
    $feedbackParams->setMeetingID('batch-feedback-meeting');
    
    $response = $bbb->feedback($feedbackParams);
    $feedbackResults[] = [
        'session_token' => $sessionToken,
        'success' => $response->success(),
        'feedback_id' => $response->success() ? $response->getFeedbackID() : null,
        'message' => $response->getMessage()
    ];
}

// Process results
$successful = array_filter($feedbackResults, fn($r) => $r['success']);
echo "Successfully submitted " . count($successful) . " out of " . count($feedbackResults) . " feedback entries.";

Response Format

The feedback API returns responses in JSON format with application/json content type.

Successful Response Example

{
  "status": "ok",
  "feedback_id": "feedback-123456",
  "session_token": "session-token-789",
  "meeting_id": "meeting456",
  "user_id": "user123",
  "rating": 4,
  "comment": "Great meeting experience!",
  "submitted_at": "2023-01-15T14:30:00Z",
  "processed": true,
  "feedback_type": "meeting_feedback",
  "additional_data": {
    "device-type": "mobile",
    "platform": "iOS"
  }
}

Minimal Response Example

{
  "status": "ok",
  "feedback_id": "feedback-minimal-789",
  "session_token": "minimal-session-token"
}

Error Response Example

{
  "status": "error",
  "message": "Invalid session token",
  "statuscode": "404"
}

Response Fields

The FeedbackResponse provides the following fields:

Required Fields

FieldTypeDescription
feedback_idStringUnique identifier for the feedback submission
session_tokenStringThe session token used for the feedback submission

Optional Fields

FieldTypeDescription
meeting_idStringMeeting ID if provided in the request
user_idStringUser ID if provided in the request
ratingIntegerRating value if provided in the request
commentStringComment text if provided in the request
submitted_atStringTimestamp when the feedback was submitted
processedBooleanWhether the feedback has been processed
feedback_typeStringType/category of feedback
additional_dataArrayAdditional metadata about the feedback

Response Handling

$response = $bbb->feedback($feedbackParams);

if ($response->success()) {
    // Basic information
    echo "Feedback ID: " . $response->getFeedbackID();
    echo "Session Token: " . $response->getSessionToken();
    
    // Optional information
    if ($response->getMeetingID()) {
        echo "Meeting ID: " . $response->getMeetingID();
    }
    
    if ($response->getUserID()) {
        echo "User ID: " . $response->getUserID();
    }
    
    if ($response->getRating()) {
        echo "Rating: " . $response->getRating();
    }
    
    if ($response->getComment()) {
        echo "Comment: " . $response->getComment();
    }
    
    if ($response->getSubmittedAt()) {
        echo "Submitted At: " . $response->getSubmittedAt();
    }
    
    echo "Processed: " . ($response->getProcessed() ? 'Yes' : 'No');
    
    // Additional data handling
    $additionalData = $response->getAdditionalData();
    foreach ($additionalData as $key => $value) {
        echo "Additional Data - {$key}: {$value}";
    }
    
} else {
    echo "Error: " . $response->getMessage();
    echo "Status Code: " . $response->getStatusCode();
}

Rating Guidelines

When implementing rating collection, consider these standard practices:

5-Star Rating Scale

function getRatingLabel($rating) {
    $labels = [
        1 => 'Very Poor',
        2 => 'Poor', 
        3 => 'Average',
        4 => 'Good',
        5 => 'Excellent'
    ];
    
    return $labels[$rating] ?? 'Not Rated';
}

// Usage
$rating = 4;
echo "User rated the meeting: " . getRatingLabel($rating);

Rating Validation

function validateRating($rating) {
    // Rating should be between 1 and 5
    if ($rating !== null && ($rating < 1 || $rating > 5)) {
        throw new InvalidArgumentException('Rating must be between 1 and 5');
    }
    
    return $rating;
}

// Usage
try {
    $rating = validateRating($_POST['rating']);
    $feedbackParams->setRating($rating);
} catch (InvalidArgumentException $e) {
    echo "Invalid rating: " . $e->getMessage();
}

Comment Guidelines

Comment Length Validation

function validateComment($comment) {
    $maxLength = 1000; // Maximum comment length
    
    if (strlen($comment) > $maxLength) {
        throw new InvalidArgumentException("Comment must be less than {$maxLength} characters");
    }
    
    // Remove excessive whitespace
    $comment = preg_replace('/\s+/', ' ', trim($comment));
    
    return $comment;
}

// Usage
try {
    $comment = validateComment($_POST['comment'] ?? '');
    if (!empty($comment)) {
        $feedbackParams->setComment($comment);
    }
} catch (InvalidArgumentException $e) {
    echo "Invalid comment: " . $e->getMessage();
}

Comment Sanitization

function sanitizeComment($comment) {
    // Basic sanitization - remove HTML tags and special characters
    $comment = strip_tags($comment);
    $comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
    
    return $comment;
}

// Usage
$rawComment = $_POST['comment'] ?? '';
$cleanComment = sanitizeComment($rawComment);
$feedbackParams->setComment($cleanComment);

Error Handling

Common error scenarios and their handling:

$response = $bbb->feedback($feedbackParams);

if (!$response->success()) {
    $message = $response->getMessage();
    $statusCode = $response->getStatusCode();
    
    switch ($statusCode) {
        case '400':
            // Bad request - invalid parameters
            echo "Invalid feedback parameters provided";
            break;
            
        case '401':
            // Unauthorized - invalid checksum or secret
            echo "Authentication failed";
            break;
            
        case '404':
            // Not found - invalid session token
            echo "Invalid or expired session token";
            break;
            
        case '429':
            // Too many requests - rate limiting
            echo "Too many feedback submissions. Please try again later.";
            break;
            
        case '500':
            // Internal server error
            echo "Server error occurred. Please try again later.";
            break;
            
        default:
            echo "Unknown error: " . $message;
    }
}

Best Practices

1. Timing

  • Collect feedback immediately after the meeting ends
  • Consider follow-up emails for longer feedback collection periods

2. User Experience

  • Keep the feedback form simple and quick to complete
  • Use clear rating scales and descriptive labels
  • Provide optional comment fields for detailed feedback

3. Data Privacy

  • Inform users about how their feedback will be used
  • Consider anonymizing feedback data for analysis
  • Follow data protection regulations (GDPR, CCPA, etc.)

4. Rate Limiting

  • Implement client-side rate limiting to prevent spam
  • Consider server-side validation for multiple submissions

5. Error Handling

  • Provide clear error messages to users
  • Implement retry logic for temporary failures
  • Log feedback submission failures for debugging

Integration Examples

Web Application Integration

// In your meeting end controller
public function submitFeedback(Request $request) {
    try {
        $sessionToken = $request->input('session_token');
        $rating = $request->input('rating');
        $comment = $request->input('comment');
        
        $feedbackParams = new FeedbackParameters($sessionToken);
        
        if ($rating) {
            $feedbackParams->setRating((int)$rating);
        }
        
        if ($comment) {
            $feedbackParams->setComment($comment);
        }
        
        $bbb = new BigBlueButton();
        $response = $bbb->feedback($feedbackParams);
        
        if ($response->success()) {
            return response()->json([
                'success' => true,
                'feedback_id' => $response->getFeedbackID(),
                'message' => 'Thank you for your feedback!'
            ]);
        } else {
            return response()->json([
                'success' => false,
                'message' => $response->getMessage()
            ], 400);
        }
        
    } catch (Exception $e) {
        return response()->json([
            'success' => false,
            'message' => 'An error occurred while submitting feedback'
        ], 500);
    }
}

JavaScript/AJAX Integration

// Frontend feedback submission
function submitFeedback(sessionToken, rating, comment) {
    const data = {
        sessionToken: sessionToken,
        rating: rating,
        comment: comment
    };
    
    fetch('/api/feedback', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            alert('Thank you for your feedback!');
            console.log('Feedback ID:', data.feedback_id);
        } else {
            alert('Error: ' + data.message);
        }
    })
    .catch(error => {
        console.error('Error submitting feedback:', error);
        alert('An error occurred while submitting feedback');
    });
}

// Usage
submitFeedback('user-session-token', 4, 'Great meeting experience!');

Analytics and Reporting

Feedback Summary

function generateFeedbackSummary($feedbackResponses) {
    $totalFeedback = count($feedbackResponses);
    $averageRating = 0;
    $ratingDistribution = [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0];
    
    foreach ($feedbackResponses as $response) {
        if ($response->getRating()) {
            $rating = $response->getRating();
            $averageRating += $rating;
            $ratingDistribution[$rating]++;
        }
    }
    
    if ($totalFeedback > 0) {
        $averageRating = $averageRating / $totalFeedback;
    }
    
    return [
        'total_feedback' => $totalFeedback,
        'average_rating' => round($averageRating, 2),
        'rating_distribution' => $ratingDistribution
    ];
}

This feedback API provides a standardized way to collect user feedback, enabling continuous improvement of the BigBlueButton platform through structured user input.

Recordings

Manage Recordings

getRecordings

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetRecordingsParameters;

$bbb              = new BigBlueButton();
$recordingParams  = new GetRecordingsParameters();

// optionally filter by meeting ids, recording ids, state or metadata
$recordingParams->setMeetingId('my-meeting-id');
$recordingParams->setState('published');

$response = $bbb->getRecordings($recordingParams);

if ($response->success()) {
    foreach ($response->getRecords() as $recording) {
        // each recording exposes id, meetingId, name, state, playback formats, ...
        echo $recording->getRecordId() . ': ' . $recording->getName() . PHP_EOL;
    }
}

Note that BigBlueButton needs several minutes to process a recording until it becomes available. You can follow the processing with bbb-record --watch on the server.

publishRecordings

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\PublishRecordingsParameters;

$bbb = new BigBlueButton();

$publishParams = new PublishRecordingsParameters($recordingId, true); // true = publish, false = unpublish
$response      = $bbb->publishRecordings($publishParams);

updateRecordings

Updates the metadata of a recording:

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\UpdateRecordingsParameters;

$bbb = new BigBlueButton();

$updateParams = new UpdateRecordingsParameters($recordingId);
$updateParams->addMeta('presenter', 'John Doe');

$response = $bbb->updateRecordings($updateParams);

deleteRecordings

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\DeleteRecordingsParameters;

$bbb                 = new BigBlueButton();
$deleteRecordingsParams = new DeleteRecordingsParameters($recordingId); // get from "getRecordings"
$response            = $bbb->deleteRecordings($deleteRecordingsParams);

if ($response->success()) {
    // recording deleted
}

Manage Tracks

Caption/subtitle tracks can be attached to recordings as WebVTT files.

getRecordingTextTracks

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\GetRecordingTextTracksParameters;

$bbb     = new BigBlueButton();
$response = $bbb->getRecordingTextTracks(new GetRecordingTextTracksParameters($recordingId));

if ($response->success()) {
    foreach ($response->getTracks() as $track) {
        echo $track->getHref() . ' (' . $track->getLang() . ')' . PHP_EOL;
    }
}

putRecordingTextTrack

Uploads a caption track. The file is sent as multipart form-data; kind is either subtitles or captions:

use BigBlueButton\BigBlueButton;
use BigBlueButton\Parameters\PutRecordingTextTrackParameters;

$bbb = new BigBlueButton();

$trackParams = new PutRecordingTextTrackParameters($recordingId, 'subtitles', 'en', 'English');
$trackParams->setTrackFile('/path/to/captions.en.vtt');

$response = $bbb->putRecordingTextTrack($trackParams);

if ($response->isUploadTrackSuccess()) {
    // track uploaded, it will appear in getRecordingTextTracks
}

The upload works with both transports — the built-in curl transport and any injected PSR-18 http client.

Hooks

Web hooks let your application receive HTTP POST callbacks whenever an event happens on the BigBlueButton server — a meeting is created or ends, a user joins or leaves, a recording is published, etc. The library manages the hook lifecycle through the hooksCreate, hooksList and hooksDestroy API calls.

Creating a hook

use BigBlueButton\BigBlueButton;
use BigBlueButton\Enum\WebHookEvent;
use BigBlueButton\Parameters\HooksCreateParameters;

$bbb = new BigBlueButton();

$hooksCreateParams = new HooksCreateParameters('https://app.example.com/hooks/callback');

// optionally: restrict the hook to one meeting
$hooksCreateParams->setMeetingId('my-meeting-id');

// optionally: only receive specific events (BBB 2.5+)
$hooksCreateParams->setEventId([WebHookEvent::USER_JOINED, WebHookEvent::USER_LEFT]);

// optionally: receive the raw event payloads instead of the processed ones
$hooksCreateParams->setGetRaw(true);

$response = $bbb->hooksCreate($hooksCreateParams);

if ($response->success()) {
    $hookId = $response->getHookId();
}

The callback URL receives a POST request with the event data for every matching event. A hook registered without a meeting id is global and receives events of all meetings on the server.

Listing hooks

$response = $bbb->hooksList();

foreach ($response->getHooks() as $hook) {
    echo $hook->getHookId() . ' -> ' . $hook->getCallbackUrl() . PHP_EOL;
}

Destroying a hook

use BigBlueButton\Parameters\HooksDestroyParameters;

$response = $bbb->hooksDestroy(new HooksDestroyParameters($hookId));

Events

The WebHookEvent enum lists all events the server can deliver, among them:

  • Meeting lifecycle: meeting-created, meeting-ended, meeting-recording-started / -stopped
  • Users: user-joined, user-left, user-emoji-changed, user-raise-hand-changed, presenter assignments
  • Media: audio/camera/screenshare state changes, chat-group-message-sent
  • Recordings processing: rap-* events (archive, process, publish steps) and rap-published / rap-deleted
  • Polls and pads: poll-started, poll-responded, pad-content

Hashing on older servers

Important

BBB servers below 3.0 accept only SHA-1 checksums for the webhooks endpoints. Since the library cannot detect the server version, hook URLs are always built with SHA-1 (safe on every server version); set the HASH_ALGO_FOR_HOOKS environment variable to use a different algorithm for hooks, e.g. sha256 on servers 3.0 and above.

Server Configuration

The library connects to the BigBlueButton integration API, which is protected by a shared secret. Two pieces of information from your server are needed:

  • BBB_SERVER_BASE_URL — the base URL of your server’s API, always ending with /bigbluebutton/ (for example https://bbb.example.com/bigbluebutton/).
  • BBB_SECRET — the shared secret of the server.

Retrieving URL and secret

Run the following command on your BigBlueButton server:

bbb-conf --secret

It prints both values, for example:

URL: https://bbb.example.com/bigbluebutton/
Secret: 8cd8ef52e8e101574e400365b55e11a6

Providing them to the library

The recommended way are the environment variables BBB_SERVER_BASE_URL and BBB_SECRET (see Getting Started). How to set environment variables depends on your hosting: SetEnv for Apache2 (e.g. in /etc/apache2/envvars), fastcgi_param for nginx, .env for Laravel, etc. Keep the secret out of your source code repository.

Alternatively pass them programmatically:

use BigBlueButton\BigBlueButton;

$bbb = new BigBlueButton('https://bbb.example.com/bigbluebutton/', 'your-secret');

Checksums and hashing algorithms

Every API call is signed with a checksum of methodName + queryString + secret. The library uses SHA-256 by default, which every BigBlueButton 2.3+ server accepts. Older servers accepted SHA-1 only; if you operate one, the algorithm can be configured via the UrlBuilder.

Note

For BBB servers below 3.0 the webhooks endpoints only accept SHA-1 checksums. The library therefore always signs hook calls with SHA-1; see Hooks for the HASH_ALGO_FOR_HOOKS override.

How to Contribute

Contributions are welcome — bug fixes, new API support, documentation and tests. This page explains the workflow; the library objectives describe the direction of the project.

Getting started

git clone https://github.com/bigbluebutton/bigbluebutton-api-php.git
cd bigbluebutton-api-php
composer install
vendor/bin/captainhook install   # installs the git hooks, if not done automatically

To run the tests against your own BigBlueButton server, copy .env to .env.local and set BBB_SERVER_BASE_URL and BBB_SECRET (see Testing). .env.local is git-ignored — never commit server credentials.

Workflow

  1. Fork the repository and create a feature branch from develop.
  2. Make your changes in small, self-contained commits (one topic per commit).
  3. Ensure all quality gates pass (see below).
  4. Open a pull request against develop and describe what changed and why. For new API parameters or endpoints, reference the BigBlueButton API documentation or the server source that specifies them.

Quality gates

The following must pass before every commit (the pre-commit hooks run them for you):

composer code-fix     # php-cs-fixer (style)
composer code-check   # PHPStan (level 8)
composer code-test    # PHPUnit (incl. live tests against the configured server)

Do not skip hooks with --no-verify. If a gate fails, fix the cause rather than bypassing it.

Commit message convention

We follow Chris Beams’ commit message style: a short imperative subject line (max 50 characters, no trailing period) and an optional body wrapped at 72 characters. Reference the GitHub issue number in the subject or body when applicable (e.g. (#223)).

What to contribute

  • New endpoints / parameters: mirror the official BigBlueButton API, add parameter + response classes, fixtures captured from a real server, unit tests, integration tests and a documentation page.
  • Bug fixes: include a failing test that proves the bug, then the fix.
  • Documentation: the mdBook sources live in docs/src/; keep examples runnable and verify them against a real server where possible.

For details see the Style Guide, Testing and Documentation pages.

Style Guide

PHP code style

The code style is enforced by PHP-CS-Fixer with the configuration in .php-cs-fixer.php (including a custom StrlenFixer rule in dev/Util/). Before every commit, run:

composer code-fix

The pre-commit hooks run the same tool in dry-run mode and reject commits with unformatted code.

Static analysis

PHPStan analyses src/ and tests/ at level 8:

composer code-check

All findings must be resolved; the pre-commit hook enforces it. When a genuine false positive cannot be avoided, use a narrow @phpstan-ignore-line or @phpstan-ignore-next-line with a short justification — never disable the rule globally.

Conventions worth knowing

  • Typed everything: properties, parameters and return types are declared throughout; null is explicit (?string), never implicit.
  • API parameter mapping: getter methods carry the #[ApiParameterMapper(attributeName: '...')] attribute that binds them to the query parameter name used by the BBB server.
  • Value sets as enums: closed parameter sets (layouts, roles, guest policies, presenter policies, disabled features, webhook events) are backed by string enums in BigBlueButton\Enum.
  • Backwards compatibility: former members are kept as deprecated stubs rather than removed (see the library objectives).
  • Comments state constraints the code cannot express — not what the next line does.

Commit messages

We follow Chris Beams’ commit message style: an imperative subject line of at most 50 characters without a trailing period, optionally a body wrapped at 72 characters. Reference the GitHub issue where applicable, e.g. (#223).

Testing

Test landscape

The suite (composer code-test) combines three kinds of tests:

  1. Offline unit tests — parameters (HTTP query generation), responses (fixtures captured from real servers), core value objects and the API methods tested against a stub PSR-18 client (StubHttpClient). They need no BigBlueButton server.
  2. Live integration testsBigBlueButtonTest and FixturesTest run against a real BigBlueButton server configured via .env.local.
  3. Dual-transport testsBigBlueButtonHttpClientTest and FixturesHttpClientTest repeat the live suites with an injected PSR-18 http client instead of curl, proving both transports behave identically.

Connecting a test server

Copy .env to .env.local and configure:

BBB_SERVER_BASE_URL=https://your-bbb-server.example.com/bigbluebutton/
BBB_SECRET=your-secret

.env.local is git-ignored — never commit server credentials. The live tests create, join and end meetings and create/destroy hooks on that server; use a dedicated test server.

Running

composer code-test                              # full suite (offline + live)
./vendor/bin/phpunit --filter testApiVersion    # a single test
./vendor/bin/phpunit tests/Parameters/          # a single directory

Coverage

Regular runs do not collect coverage. To generate an HTML report (requires a coverage driver such as Xdebug or PCOV):

composer code-coverage

The report lands in ./var/coverage/. The project maintains 100 percent class, method and line coverage; practically unreachable defensive guards are marked with @codeCoverageIgnore.

Fixtures

Server responses are captured as fixtures in tests/fixtures/responses/. FixturesTest validates for every XML fixture that the live server still answers with the same structure, so format changes on the server surface early. Fixtures that cannot be validated against a live server (e.g. they require a processed recording) are listed with reasons in FixturesTest::$xmlFilesThatAreNotTestable.

Documentation

This documentation is built with mdBook. The sources live in docs/src/; the build output goes to docs/book/ (git-ignored).

  1. Install rust

  2. Install mdbook

cargo install mdbook
  1. Install this to ensure external links will be opened in a new tab https://crates.io/crates/mdbook-external-links
cargo install mdbook-external-links
  1. Install extention for alerts https://crates.io/crates/mdbook-alerts
cargo install mdbook-alerts

Caution

??? How to prevent the markdown below of being parsed?

> [!NOTE]  
> Highlights information that users should take into account, even when skimming.

> [!TIP]
> Optional information to help a user be more successful.

> [!IMPORTANT]  
> Crucial information necessary for users to succeed.

> [!WARNING]  
> Critical content demanding immediate user attention due to potential risks.

> [!CAUTION]
> Negative potential consequences of an action.

  1. build the book locally
mdbook serve --open

Full Usage Example

Introduction

You have been using BigBlueButton for years or you are still discovering it, and you have PHP within your solutions sphere and considering managing your BigBlueButton meetings with PHP, we are writing this tutorial right for you and your team.

BigBlueButton officially offers a PHP library to use for its API. In this tutorial you will learn how to use this PHP library to create a meeting then join it.

Pre-requisites

Before we can show you how to use the library, it is important to have the following point done:

  • BigBlueButton server installed. Easy enough, it takes 15 minutes or less. Just follow this link https://bigbluebutton.org/2018/03/28/install-bigbluebutton-in-15-minutes/ if not already done.
  • PHP 8.2 or higher.
  • curl, mbstring, SimpleXML and JSON PHP extensions. They are active by default in most PHP distributions.
  • A running HTTP server, Apache2 or nginx.
  • Composer PHP dependency manager pre-installed.

Installation and configuration

First, we need to create our composer project.

composer init –name 'bigbluebutton-join-form'

Then we need to add the library available on packagist.

composer require bigbluebutton/bigbluebutton-api-php

Once we have defined the required dependency, we need to install it using the command below.

composer install -o --no-dev

Adding --no-dev options, means that we omit development packages that are mainly used to unit test the library.

The library package has now been downloaded to vendor directory in your project root. A configuration final step is required for the library.

As you know, the call BigBlueButton API you need the server URL and the shred secret. You can get them from you BigBlueButton server with ‘bbb-conf’ http://docs.bigbluebutton.org/install/bbb-conf.html#–secret

Once you have them, create two environment variables. For Apache2 you can use the SetEnv directive or the fastcgi_param for nginx. For Apache2, we advise putting the variables in the /etc/apache2/envvars to keep themaway from your source code repository.

BBB_SECRET='8cd8ef52e8e101574e400365b55e11a6'

BBB_SERVER_BASE_URL='http://test-install.blindsidenetworks.com/bigbluebutton/'

Set up a basic join meeting form

Let’s go ahead and create our HTML form to join BigBlueButton meeting. The contact form will contain the following fields: username, a combo-box for the meeting name, a second combo-box for the user role and a checkbox for the client type.

Your form should look like the image below, and the source code is just below the image.

<!DOCTYPE html>
<html lang="en">
<style>
    body {
        padding     : 20px 40px;
        font-size   : 14px;
        font-family : Verdana, Tahoma, sans-serif;
    }

    h2 {
        color : #273E83;
    }

    input:not([type=checkbox]), select {
        border-radius : 3px;
        padding       : 10px;
        border        : 1px solid #E2E2E2;
        width         : 200px;
        color         : #666666;
        box-shadow    : rgba(0, 0, 0, 0.1) 0 0 4px;
    }

    input:hover, select:hover,
    input:focus, select:focus {
        border     : 1px solid #273E83;
        box-shadow : rgba(0, 0, 0, 0.2) 0 0 6px;
    }

    .form label {
        margin-left : 12px;
        color       : #BBBBBB;
    }

    .submit input {
        background-color : #273E83;
        color            : #FFFFFF;
        border-radius    : 3px;
    }

</style>
<head>
    <meta charset="UTF-8">
    <title>BigBlueButton Join Meeting - PHP Form</title>
</head>
<body>
<h2>BigBlueButton Join Meeting - PHP Form</h2>

<form class="form" action="join_bbb.php" method="post">

    <p class="username">
        <input type="text" name="username" id="username" placeholder="University Teacher"/>
        <label for="username">Username</label>
    </p>

    <p class="role">
        <select name="role" id="role">
            <option value="moderator">Moderator</option>
            <option value="attendee">Attendee</option>
        </select>
        <label for="role">Role</label>
    </p>

    <p class="meeting">
        <select name="meeting" id="meeting">
            <option value="mc">Molecular Chemistry</option>
            <option value="it">Information Theory</option>
            <option value="pm">Project Management</option>
        </select>
        <label for="meeting">Course</label>
    </p>

    <p class="submit">
        <input type="submit" value="Join"/>
    </p>
</form>
</body>
</html>

The HTML form is now ready. Let’s see how to handle posted data step by step. All data will be sent then processed by join-bbb.php file.

Preparing PHP form processor

Do you remember we used composer to install the library? Composer creates a file named autoload.php inside vendor directory. Just import it to load the necessary classes.

<?php

require_once './vendor/autoload.php';

After asking PHP to use the file ./vendor/autoload.php to handle the necessary classes loading. We define our meeting names in the $meetings, then we define the $passwords, both in associative arrays.

// Define meetings names
$meetings = array('mc' => 'Molecular Chemistry',
                  'it' => 'Information Theory',
                  'pm' => 'Project Management');

$passwords = array('moderator' => 'mPass',
                   'attendee'  => 'aPass');

The PHP API offers an easy way to handle calls. Creating an instance of BigBlueButton class without giving any parameter. After it we are storing the meeting id we got from our form inside the $meetingId variable.

// Init BigBlueButton API
$bbb = new BigBlueButton();
$meetingId = $_POST['meeting'];

Creating the meeting

To create a meeting, only two parameters are mandatory: the meeting ID and the meeting name. For security reasons we discourage leaving the moderator password and the attendee password empty. For that reason, we are filling them in the CreateMeetingParameters instance.

// Create the meeting
$createParams = new CreateMeetingParameters($meetingId, $meetings[$meetingId]);
$createParams = $createParams->setModeratorPassword($passwords['moderator'])
                             ->setAttendeePassword($passwords['attendee']);
$bbb->createMeeting($createParams);

Joining the meeting

A meeting can be joined by two different ways. The first way is to let the BigBlueButton server do the redirection for you. The second way is to ask for an XML response then construct the URL using getSessionToken. Both of the methods are detailed below.

Joining the meeting is done in two steps. In the first step we create an instance of CreateMeetingParameters and fill the previously saved $meetingId, then username and role values from POST values. The third required parameter is password, the role of the user is determined by the system depending on the provided password. For that reason we will read it from $passwords using the $_POST['role'] key.

// Send a join meeting request
$joinParams = new JoinMeetingParameters($meetingId, $_POST['username'], $passwords[$_POST['role']]);

Following the server redirection

We set redirect to true if we want an immediate redirection to the meeting.

// Ask for immediate redirection
$joinParams->setRedirect(true)

Lastly, we ask PHP to follow the join meeting redirection using the header function. The redirection will be done by BigBlueButton by calling $bbb->getJoinMeetingURL($joinParams)). You should now see the meeting page.

// Join the meeting by redirecting the user to the generated URL
header('Status: 301 Moved Permanently', false, 301);
header('Location:' . $bbb->getJoinMeetingURL($joinParams));

Storing join response to join manually

There is also a different way to join a meeting. To achieve it, we set redirect to false.

// Let the prorgrammer do the redirection later
$joinParams->setRedirect(false)

In this particular case the server will return an XML response. To handle it you need to call the joinMeeting method.

$joinResponse = $bbb->joinMeeting($joinParams);

Then we prepare the server URL for joining the meeting.

// Prepare the server URL
$bbbServerUrl = "https://my-bbb-server.com";

The user is redirected to the HTML5 client using the session token of the join response.

// Join the HTML5 client
header('Status: 301 Moved Permanently', false, 301);
header('Location:' . $bbbServerUrl . "/html5client/join?sessionToken=" . $joinResponse->getSessionToken());

Conclusion

You have discovered how to setup a BigBlueButton meeting then join it using the PHP API client library. Go ahead and explore the library features to implement your own meeting management system for BigBlueButton.

FAQ

When I join a meeting, my users see an error / the client misbehaves. What is wrong?

The most common trap: joinMeeting() executes the join server-side, so the user’s browser never receives the session cookie the BBB server sets on join. The standard flow is to redirect the user’s browser to a generated join URL:

$joinUrl = $bbb->getJoinMeetingURL($joinMeetingParameters);
header('Location: ' . $joinUrl);

Use joinMeeting() (with setRedirect(false)) only when you explicitly need the join response — e.g. session tokens for API-driven clients. See also the Joining chapter.

Do I need allowRequestsWithoutSession=true?

Only if you join meetings server-side (see above) or drive clients that cannot hold a session. It weakens the meeting’s security — prefer the redirect flow.

Which BBB server versions are supported?

The library tracks the current BigBlueButton API across BBB 2.x, 3.x and 4.x: parameters removed on newer servers remain available (marked deprecated) so integrations against older servers keep working, and new server parameters are added as soon as they are documented.

The feedback endpoint returns 404

The /api/feedback endpoint is reserved in the BBB server source but not routed on current releases. The library ships the implementation marked experimental; it will start working once a BBB release actually provides the endpoint.

How do I get the URL and secret of my server?

bbb-conf --secret on the server — see Server Configuration.

Can I use my own HTTP client (Guzzle, Symfony)?

Yes — any PSR-18 client with PSR-17 factories can be injected, see HTTP Client. curl stays the dependency-free default.

What does the library do with cookies?

It captures only the JSESSIONID the server sets on some calls, validates it, and exposes it via getJSessionId(). No cookies are persisted or sent back — details in Cookies and the JSESSIONID.

Where do I report bugs or request features?

On GitHub — with a reproducing code sample against the current release if possible.

External Links