A JavaScript library for interacting with StreamBIM from within an embedded widget, as well as for using StreamBIM in embedded mode.
Embed the StreamBIM viewer in your own page/app and control it via a promise‑based JavaScript API. This README consolidates the behavior shown in the demo apps so you can quickly wire up integrations.
For migrating to v3, read this section for instructions.
StreamBIM widgets have to be whitelisted and then enabled per StreamBIM project. Please contact [email protected] if you want to set up a custom widget for one or more projects.
If your widget requires authentication you have two options:
- Handle the authentication in the widget itself
- Use OpenID Connect and provide us with your identity server etc. StreamBIM will then open your login screen in a popup and persist the token per user across sessions.
TL;DR
- Load
streambim-widget-api.min.js.StreamBIM.connectToChild(iframe, callbacks)to establish a connection.- Call API methods on the
StreamBIM.APIproxy (they all return Promises).
- Install & Build
- Quick Start
- Events (callbacks you can subscribe to)
- Authentication
- Styling & UI Controls
- API Reference
- Examples
Include the distributed bundle in your page (from dist/ in this repo or your build pipeline):
<script src="streambim-widget-api.min.js"></script>You host the StreamBIM viewer in an <iframe> that points to your project/building and set embedded=true in the hash:
<iframe id="streambim_target" src="https://<your-streambim-host>/#/viewer?projectId=...&embedded=true"></iframe>To run a widget inside StreamBIM, call something like this from your widget:
import StreamBIM from 'streambim-widget-api';
const methods = {
pickedObject: function (result) {
console.log('Clicked at ' + result.guid);
}
}
StreamBIM.connectToParent(window, methods).then(function() {
console.log('Connected!');
});To run StreamBIM in embedded mode, first create an iframe, open a StreamBIM project with embedded=true in the URL parameters, and then call the connectToChild method.
import StreamBIM from 'streambim-widget-api';
const iframe = document.getElementById('streambim_target');
const projectId = PROJECT_ID;
iframe.src = 'https://app.streambim.com/webapp/default/#/viewer?projectId=' + projectId + '&embedded=true';
const methods = {
pickedObject: function (result) {
console.log('Clicked at ' + result.guid);
}
}
StreamBIM.connectToChild(iframe, methods).then(function() {
console.log('Connected!');
});All API calls below return a Promise.
Register these in the second argument to connectToChild(iframe, callbacks):
pickedObject(result)→ Fires when the user clicks an object.resultcontains{ guid, point? }wherepointis[x,y,z]if available.spacesChanged(guids)→ When the active space changes (enter/leave), provides current space GUID(s).floorChanged(floorId)→ When the active floor changes.cameraChanged(cameraState)→ On camera state updates; useful for persisting/restoring view.beforeInit()→ Hook called before init; you can set styles, sky color, nav mode, hide UI, perform initial commands, etc.
setAuthToken(token: string): Promise<boolean>— Provide a bearer token the embedded viewer should use for API requests. Call this inbeforeInitif you don’t rely on existing session.
setStyles(css: string): Promise<boolean>— Inject CSS into the embedded viewer (e.g., hide buttons, recolor UI).setSkyColor(color: string): Promise<boolean>— Change the 3D background (e.g.,'white','#000','rgb(10,20,30)').setNavigationMode(mode: 0|1): Promise<boolean>— 0 = Person (walk), 1 = Spin (orbit).setExpanded(bool: boolean): Promise<boolean>— Expand/collapse the embedded widget container (if supported by host page).setShowExpandButton(bool: boolean): Promise<boolean>— Show/hide the expand button.toggleShowAllFloors(bool: boolean): Promise<boolean>— Toggle multi‑floor grid view on/off.
getProjectId(): Promise<string>— Returns current project ID.getUserEmail(): Promise<string>— Returns logged‑in user’s email/ID.getBuildingId(): Promise<string>— Returns current building ID.
getCameraState(): Promise<CameraState>— Get the current camera/position/target/up vectors etc.setCameraState(state: CameraState): Promise<boolean>— Set the full camera state.setCameraPosition(position: [number,number,number]): Promise<boolean>— Move camera to world position.getViewportState(): Promise<any>— Get full viewport (camera + extra viewer state) as a serializable object.setViewportState(state: any): Promise<boolean>— Restore viewport state.applyViewpoint(viewpoint: any): Promise<boolean>— Apply a saved viewpoint (semantic shortcut for setting camera & layers/etc.).
gotoObject(guid: string): Promise<boolean>— Navigate camera to object.gotoSpace(guid: string): Promise<boolean>— Navigate camera to space by GUID.gotoFloor(floorId: string|number): Promise<boolean>— Jump to floor.goHome(): Promise<boolean>— Return to home/start view (if configured).
highlightObject(guid: string): Promise<boolean>— Highlight (select) object.deHighlightObject(guid: string): Promise<boolean>— Remove highlight from a single object.deHighlightAllObjects(): Promise<boolean>— Clear all highlights.hideObject(guid: string): Promise<boolean>— Hide a single object by GUID.showObject(guid: string): Promise<boolean>— Show a previously hidden object.showAllObjects(): Promise<boolean>— Reset hidden state for all objects.highlightSystem(guid: string): Promise<boolean>— Highlight all objects belonging to a system.
getObjectInfo(guid: string): Promise<ObjectInfo>— Fetch full IFC object info & properties.getFloors(): Promise<Array<{id:string|number,name:string,height:number}>>— All floors including height.getSpaces(): Promise<string[]>— Current space GUIDs where the camera is located.valuesForObjectProperty(prop: string): Promise<any[]>— Distinct values for apsetName~propKeypair across the model.
findObjects(query: { key: string, value: string, limit?: number }): Promise<string[]>— Find GUIDs matching a property filter.applyObjectSearch(query: ObjectSearchQuery, replace?: boolean): Promise<string[]>— Apply a search as the active selection (optionally replacing any current set). Supports structured rules, paging and sorting.getObjectInfoForSearch(query: ObjectSearchQuery): Promise<ObjectInfo[]>— Run a search and return info for the result set.resetObjectSearch(): Promise<boolean>— Clear active search/selection.setSearchVisualizationMode(mode: 'HIDDEN'|'FADED'|'ORIGINAL'): Promise<boolean>— How non‑matching elements are shown while a search is active.zoomToSearchResult(): Promise<boolean>— Frame camera to the current active selection.quickSearch(freetext: string): Promise<any>— Search objects/properties by free text; returns matches for UI display.
Search query shape (examples):
// simple key/value
{ key: 'System Global Id', value: '08CWGl08rCWBFXLXyoG6Rs', limit: 100 }
// IFC rules with operators and paging/sort
{
filter: {
rules: [[{
buildingId: '1000', psetName: 'BaseQuantities', propKey: 'Height', propValue: '2000', operator: '>'
}]]
},
page: { limit: 1000, skip: 0 },
sort: { field: 'Name', descending: false }
}colorCodeObjects(map: Record<GUID,string>): Promise<boolean>— Color code objects by GUID→color (hex). Clears color coding when empty map.colorCodeObjectsWithLegends({ data: Record<GUID,string>, legends: Record<string,string> }): Promise<boolean>— Color code objects and display legend labels/colors.colorCodeSpaces(map: Record<GUID,string>): Promise<boolean>— Color code spaces by GUID→color (hex). Clears color coding when empty map.colorCodeSpacesWithLegends({ data: Record<GUID,string>, legends?: Record<string,string> }): Promise<boolean>— Color code spaces by GUID with optional legends.colorCodeByProperty({ pset?: string, propertyKey?: string } = {}): Promise<boolean>— Auto color‑code by property value (viewer decides buckets/colors).
getLayers(): Promise<Record<string, boolean>>— Current layer visibility map.setLayers(layers: Record<string, boolean>): Promise<boolean>— Apply a layer visibility map.showGrids(): Promise<boolean>— Show grid lines.hideGrids(): Promise<boolean>— Hide grid lines.
takeScreenshot(): Promise<dataURL>— PNG data URL of current 3D view.getMapImage(opts: { width: number, height: number, resolution: number }): Promise<dataURL>— Generate overview/detail map image (resolution in meters/pixel).getAnnotatedFloorplan(position: [number,number,number]): Promise<dataURL|blobURL>— Produce a floorplan PDF with an annotation marker near a 3D pick/camera position (usepickedObject.pointorcameraState.position).
createObject({ center: [x,y,z], name: string }): Promise<GUID>— Create a simple annotation object at a world coordinate.
setExpanded(bool: boolean): Promise<boolean>— Expand/collapse the embedded widget (if host UI supports it).setShowExpandButton(bool: boolean): Promise<boolean>— Show/hide expand button.
makeApiRequest({ url: string, body?: any, method?: 'GET'|'POST'|'PUT'|'DELETE', accept?: string, contentType?: string }): Promise<string>— Perform an authenticated request from inside the viewer context (helpful for IFC searches/exports). Returns the raw response body (often JSON text) so you canJSON.parseit.
const data = { 'SpaceGuidA': '7d7d7d', 'SpaceGuidB': '4abb32', 'SpaceGuidC': 'b90c0c' };
const legends = { 'Not started': '7d7d7d', 'On track': '4abb32', 'Over due': 'b90c0c' };
await StreamBIM.API.colorCodeSpaces({ data, legends });
await StreamBIM.API.zoomToSearchResult();const selected = await StreamBIM.API.getObjectInfo(guid);
const systemGuid = selected.properties['System Global Id'][0];
await StreamBIM.API.applyObjectSearch({ key: 'System Global Id', value: systemGuid, limit: 100 }, true);
await StreamBIM.API.setSearchVisualizationMode('FADED');
await StreamBIM.API.zoomToSearchResult();const screenshot = await StreamBIM.API.takeScreenshot();
document.querySelector('#img').src = screenshot;
const map = await StreamBIM.API.getMapImage({ width: 1024, height: 768, resolution: 5 });// 1) create search
const res = await StreamBIM.API.makeApiRequest({
url: '/pgw/project-XXXX/api/v1/ifc-searches',
method: 'POST',
body: { rules: [[{ buildingId: '1000', propKey: '@kind', propValue: 'Space' }]] }
});
const { searchId } = JSON.parse(res);
// 2) export result
const fieldNames = btoa('GUID|Name|Long Name|Description');
const json = await StreamBIM.API.makeApiRequest({
url: `/pgw/project-XXXX/api/v1/ifc-searches/export/json?searchId=${searchId}&fieldUnion=true&fieldNames=${fieldNames}&page[limit]=1000&page[skip]=0`
});
const spaces = JSON.parse(json).data;- All methods return a
Promise. On error, the promise rejects with{ code: string, detail?: any }. - GUIDs are StreamBIM IFC GUIDs unless a method explicitly uses a floor ID.
- Colors accept HEX strings only
Version 3 comes with a new feature and a few changes to the API.
You can now open StreamBIM in a new window and interact with it:
import StreamBIM from 'streambim-widget-api';
const streamBimUrl = 'https://app.streambim.com/webapp/default/#/viewer?projectId=' + projectId + '&embedded=true';
const streamBimWindow = window.open(streamBimUrl, 'streamBimWindow', 'width=1200,height=800');
const methods = {
pickedObject: function (result) {
console.log('Clicked at ' + result.guid);
}
}
StreamBIM.connectToWindow(streamBimWindow, streamBimUrl, methods).then(function() {
console.log('Connected!');
});API methods are no longer mapped directly to the StreamBIM global object.
Instead, there is a new property on the StreamBIM object named API, where all API calls can be made.
Old:
const projectId = StreamBIM.getProjectId();New:
const projectId = StreamBIM.API.getProjectId();We have also renamed the old connect method to connectToParent, and changed its parameters accordingly.
This method is used for running a widget from inside StreamBIM.
Old
import StreamBIM from 'streambim-widget-api';
const methods = {
pickedObject: function (result) {
console.log('Clicked at ' + result.guid);
}
}
StreamBIM.connect(methods).then(function() {
console.log('Connected!');
});New
import StreamBIM from 'streambim-widget-api';
const methods = {
pickedObject: function (result) {
console.log('Clicked at ' + result.guid);
}
}
StreamBIM.connectToParent(this.window, methods).then(function() {
console.log('Connected!');
});