Lightning Device Map Widget¶
Display an interactive Google Map showing all active Lightning device locations for your agency directly on your website using the Lightning Device Map Widget.
This guide covers:
- Creating a Private Lucit Application with the Widgets capability
- Granting the correct operator permissions
- Creating a Public token for your website
- Embedding the Lightning Device Map Widget on your site
- Configuring map appearance, marker icons, and info windows
- Customizing the container and map dimensions
This widget is primarily designed for Media Owner / Operator websites that want to display an interactive map of their screen network.
Prerequisites¶
Before you start, you should:
- Have a Lucit account with access to:
- Your Personal Profile (for creating apps)
- At least one Agency / Operator Account (for attaching the app to your device network)
- Your Operator account has the Lighting App and at least 1 active Lighting Device. Learn more at https://www.lucit.cc/lightning
- Be able to:
- Edit the HTML / template of your website (or manage embeds in your CMS)
- Add
<script>tags and small JavaScript configuration blocks to your pages - Have Developer Mode enabled on your profile. (
Personal Profile -> Settings -> Developer Mode) - Have a Google Maps API key with the Maps JavaScript API enabled.
See Get a Google Maps API Key for instructions.
1. Create a new Private Application¶
The widget is powered by a Lucit Application. You'll create a private app tied to your personal profile.
- Switch to your Personal Profile in Lucit.
- With Developer Mode enabled, go to Apps.
- Click New Application.
- Choose:
- Name — for example:
My Company Website Widgets - Class —
Private - Save the application.
2. Enable the Widgets capability¶
- Open your new application.
- Go to the Capabilities tab.
- Locate the Widgets capability.
- Turn the Widgets switch on.
3. Configure operator permissions¶
The widget needs permission to read device locations for your agency.
On the Permissions tab of your app, enable at least the following permissions for your agency:
agency.viewagency.viewLightningDeviceMap
These allow the widget to read the Lightning devices and their coordinates associated with your agency.
4. Create a Public token¶
The website widget uses a Public token to fetch content.
- Go to the Tokens tab of your application.
- Click New Token.
- Choose Public token.
- Click CREATE.
- Copy the generated Public Token value.
You will use this as {PUBLIC_TOKEN} in your embed code.
5. Attach the app to your Agency Account¶
- Switch from your Personal Profile to your Agency Account using the profile switcher.
- Go to Settings.
- Scroll to Apps & Data Sources.
- Click Add New.
- Find the app you just created (for example,
My Company Website Widgets) and add it.
At this point, the app is:
- Capable of serving Widgets.
- Authorized to read device locations from your agency account.
- Identified by a Public token that you can safely embed on your website.
6. Find your Agency LCUID¶
The widget requires your Agency LCUID — a unique identifier for your agency account in Lucit.
You can find it in Settings → General for your agency account. It looks like LCUID_xxxxxxxxxxxxxxxx.
7. Embed the Lightning Device Map Widget¶
The widget is configured using the global window.lcw queue and a script loaded from Lucit.
Minimal example¶
<div id="lc-map-1">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-1",
widget: "lightning_device_map",
agency_id: "{YOUR_AGENCY_LCUID}",
token: "{PUBLIC_TOKEN}",
google_maps_api_key: "{YOUR_GOOGLE_MAPS_API_KEY}"
});
</script>
<script
src="https://lucit.app/embed/v1/widgets.js"
charset="utf-8"
async></script>
Key points:
- The
<div>idmust match theidvalue in the configuration object. - Push the configuration into
window.lcwbeforewidgets.jsloads. - The script at
https://lucit.app/embed/v1/widgets.jsinitializes the widget system and renders all queued widgets. - By default the map will auto-fit to show all device locations.
8. Widget configuration reference¶
{
id: string, // required: ID of the target <div>
widget: "lightning_device_map", // required: must be exactly this string
agency_id: string, // required: your agency LCUID
token: string, // required: Public token from your Lucit app
google_maps_api_key: string, // required: Google Maps JavaScript API key
containerStyle?: { [key: string]: string }, // optional: styles applied to the outer <div>
mapOptions?: { // optional: map behavior and appearance
height?: string, // CSS height of the map, e.g. "400px" or "60vh"
zoom?: number, // initial zoom level — disables auto-fit when set
center?: { lat: number, lng: number }, // initial center — disables auto-fit when set
mapTypeId?: string, // "roadmap" | "satellite" | "hybrid" | "terrain"
gestureHandling?: string, // "cooperative" | "greedy" | "none"
infoWindow?: boolean, // show device name on marker click (default: true)
markerIcon?: string | object, // custom marker icon URL or icon object
styles?: object[], // Google Maps style array for custom colors/labels
disableDefaultUI?: boolean,
zoomControl?: boolean,
streetViewControl?: boolean,
fullscreenControl?: boolean,
mapTypeControl?: boolean,
// ...any other google.maps.MapOptions property
}
}
Required fields¶
| Field | Type | Description |
|---|---|---|
id |
string |
The id of the DOM element where the map will render |
widget |
string |
Must be "lightning_device_map" |
agency_id |
string |
Your agency LCUID (e.g. LCUID_xxxxxxxxxxxxxxxx) |
token |
string |
Public token from your Lucit application |
google_maps_api_key |
string |
Google Maps JavaScript API key |
9. Map options (mapOptions)¶
9.1 Map dimensions¶
height¶
Controls the CSS height of the rendered map. Accepts any valid CSS length value.
The width of the map always fills 100% of its container. Control the container width via containerStyle.
9.2 Viewport — zoom and center¶
By default the map auto-fits its viewport to show all device locations. Setting either zoom or center disables auto-fit and uses the explicit values instead.
zoom¶
Initial zoom level. Accepts an integer from 1 (world) to 20 (building).
See Google Maps zoom levels.
center¶
Initial map center as a { lat, lng } object.
See google.maps.LatLngLiteral.
You can combine both to set a fixed starting view:
9.3 Map type¶
mapTypeId¶
Controls the base map style. Accepted values:
| Value | Description |
|---|---|
"roadmap" |
Standard road map (default) |
"satellite" |
Satellite imagery |
"hybrid" |
Satellite with road/label overlay |
"terrain" |
Topographic relief map |
9.4 Scroll and gesture handling¶
gestureHandling¶
Controls how the map responds to scroll and touch gestures. Default is "cooperative", which is the recommended value for embedded maps — it requires the user to hold Ctrl (desktop) or use two fingers (mobile) to zoom.
See Gesture handling.
| Value | Behavior |
|---|---|
"cooperative" |
Ctrl+scroll to zoom on desktop; two-finger scroll on mobile (default) |
"greedy" |
All scroll events zoom the map — can interfere with page scrolling |
"none" |
Scroll zoom and drag pan are disabled entirely |
"auto" |
Cooperative on mobile, greedy on desktop |
9.5 Marker icon¶
markerIcon¶
Overrides the default Lucit screen marker icon. Accepts either a URL string or a Google Maps icon object.
Default icon: https://lucit.app/assets/google-maps/markers/map_icon_screen_widescreen_active.png
URL string:
Icon object (controls size, anchor point, etc.):
mapOptions: {
markerIcon: {
url: "https://example.com/my-custom-pin.png",
scaledSize: new google.maps.Size(40, 40),
anchor: new google.maps.Point(20, 40)
}
}
Note:
scaledSizeandanchormust usenew google.maps.Size()andnew google.maps.Point()respectively — plain{ width, height }objects are not accepted by the Maps API for these properties. If you need to pass these values from a non-JS context (e.g. a CMS), use a URL string instead and size the icon at the image source.
See google.maps.Icon.
9.6 Info windows¶
infoWindow¶
When true (the default), clicking a marker shows a small popup with the device name. Set to false to disable popups entirely.
9.7 Custom map styling¶
styles¶
Applies a custom visual style to the map — change colors, hide labels, suppress points of interest, etc.
See Styling the map and Cloud-based map styling.
You can generate style arrays using Snazzy Maps or Google's Map Style Wizard.
mapOptions: {
styles: [
{ featureType: "poi", elementType: "all", stylers: [{ visibility: "off" }] },
{ featureType: "transit", elementType: "all", stylers: [{ visibility: "off" }] },
{ featureType: "road", elementType: "geometry", stylers: [{ color: "#f0f0f0" }] },
{ featureType: "water", elementType: "geometry", stylers: [{ color: "#c9d6e3" }] }
]
}
9.8 UI controls¶
These mirror the standard google.maps.MapOptions control flags directly.
| Option | Type | Default | Description |
|---|---|---|---|
disableDefaultUI |
boolean |
false |
Hides all built-in controls at once |
zoomControl |
boolean |
true |
Show / hide the +/− zoom buttons |
streetViewControl |
boolean |
true |
Show / hide the Pegman (Street View) control |
fullscreenControl |
boolean |
true |
Show / hide the fullscreen button |
mapTypeControl |
boolean |
true |
Show / hide the Map / Satellite toggle |
mapOptions: {
disableDefaultUI: true,
zoomControl: true // re-enable just zoom after disabling everything else
}
10. Container styling¶
containerStyle accepts any CSS property in camelCase and is applied to the outer wrapper <div>.
Default container style when containerStyle is omitted or empty:
| Property | Default value |
|---|---|
border |
"1px solid #808080" |
borderRadius |
"5px 5px 5px 5px" |
width |
"600px" |
padding |
"25px 5px 25px 5px" |
To suppress all default styles and control layout entirely from your own CSS, pass an empty object:
Example — full-width, no border:
11. Full examples¶
Minimal — auto-fit, default styling¶
<div id="lc-map-minimal">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-minimal",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY"
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Full-width, taller map, no UI chrome¶
<div id="lc-map-fullwidth">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-fullwidth",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
containerStyle: {
width: "100%",
border: "none",
borderRadius: "12px",
padding: "0",
overflow: "hidden"
},
mapOptions: {
height: "600px",
disableDefaultUI: true,
zoomControl: true,
gestureHandling: "cooperative"
}
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Fixed center and zoom — no auto-fit¶
<div id="lc-map-fixed">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-fixed",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
mapOptions: {
height: "450px",
zoom: 7,
center: { lat: 41.8781, lng: -87.6298 },
mapTypeId: "roadmap"
}
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Satellite view, info windows disabled¶
<div id="lc-map-satellite">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-satellite",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
mapOptions: {
height: "400px",
mapTypeId: "hybrid",
infoWindow: false,
streetViewControl: false,
mapTypeControl: false
}
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Custom marker icon¶
<div id="lc-map-custom-icon">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-custom-icon",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
mapOptions: {
height: "400px",
markerIcon: "https://example.com/your-custom-pin.png"
}
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Muted color scheme — hide POIs and transit¶
<div id="lc-map-styled">Lucit Device Map</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-styled",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
containerStyle: {
width: "100%",
border: "1px solid #e0e0e0",
borderRadius: "8px",
padding: "0",
overflow: "hidden"
},
mapOptions: {
height: "480px",
disableDefaultUI: true,
zoomControl: true,
styles: [
{ featureType: "poi", elementType: "all", stylers: [{ visibility: "off" }] },
{ featureType: "transit", elementType: "all", stylers: [{ visibility: "off" }] },
{ featureType: "road", elementType: "geometry", stylers: [{ color: "#f5f5f5" }] },
{ featureType: "road", elementType: "labels.text.fill", stylers: [{ color: "#9e9e9e" }] },
{ featureType: "water", elementType: "geometry", stylers: [{ color: "#c9d6e3" }] },
{ featureType: "landscape", elementType: "geometry", stylers: [{ color: "#f9f9f9" }] }
]
}
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
Multiple maps on the same page¶
You can embed multiple maps on a single page. Each must have a unique id. The Google Maps script is loaded only once regardless of how many map widgets are on the page.
<div id="lc-map-region-north">North Region</div>
<div id="lc-map-region-south">South Region</div>
<script>
(window.lcw = window.lcw || []).push({
id: "lc-map-region-north",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
mapOptions: { height: "350px", zoom: 9, center: { lat: 45.0, lng: -93.2 } }
});
(window.lcw = window.lcw || []).push({
id: "lc-map-region-south",
widget: "lightning_device_map",
agency_id: "LCUID_YOUR_AGENCY",
token: "YOUR_PUBLIC_TOKEN",
google_maps_api_key: "YOUR_GOOGLE_MAPS_API_KEY",
mapOptions: { height: "350px", zoom: 9, center: { lat: 44.5, lng: -93.2 } }
});
</script>
<script src="https://lucit.app/embed/v1/widgets.js" charset="utf-8" async></script>
12. Render behavior¶
- The widget renders once when
widgets.jsloads and processes the queue. - After the initial render, the map is not re-fetched or re-drawn on subsequent internal ticks — the map remains stable on the page.
- If the initial API call fails, the widget resets its state so the next internal tick will retry automatically.
13. Best practices¶
-
Use a dedicated Website Widgets app
Keep widget access separate from other integrations by creating a dedicated Private application for website embeds. -
Limit permissions
Grant only the permissions required (view,viewDevices) for the relevant agency accounts. -
Use
gestureHandling: "cooperative"(the default)
This prevents the map from hijacking scroll events when embedded within a scrollable page. Only change this if the map occupies a full-page or dedicated viewport. -
Control width via
containerStyle
The map div is alwayswidth: 100%of its container. SetwidthoncontainerStyle(or let the container be sized by your page CSS by passingcontainerStyle: {}). -
Use
overflow: "hidden"withborderRadius
If you applyborderRadiustocontainerStyle, also addoverflow: "hidden"to clip the map canvas corners correctly. -
Restrict your Google Maps API key
In the Google Cloud Console, restrict your key to the specific domains where the widget will be embedded. Never use an unrestricted key in public embed code. -
Test on a non-public page first
Embed the widget on a staging or hidden URL to validate behavior before publishing.
14. Troubleshooting¶
Map does not appear¶
- Verify that:
agency_idis a valid LCUID for your agency.tokenis a valid Public token for an app with the Widgets capability.google_maps_api_keyis valid and has the Maps JavaScript API enabled in Google Cloud Console.- The
<div>with the matchingidexists in the page before the widget configuration is pushed. - Open your browser console — required-field validation errors are logged there.
Map renders but no markers appear¶
- Verify that the agency has active Lightning devices with latitude/longitude data.
- Check the browser console for API errors — a
success: falseresponse from the Lucit API will log an error. - Confirm the app is attached to the correct agency under Settings → Apps & Data Sources.
Map is blank / gray tiles¶
- The
google_maps_api_keymay be invalid, expired, or restricted to a domain that does not match the current page. - Confirm the Maps JavaScript API is enabled for the key in Google Cloud Console.
- Check the browser console for Google Maps API errors (e.g.
ApiNotActivatedMapError,InvalidKeyMapError).
Map zooms in too close on load¶
- This can happen when only one device location is returned. The widget handles this case automatically by centering on the single device at zoom level 14 rather than using
fitBounds. - If this zoom level is too close or too far for your network, override it with an explicit
zoomandcenterinmapOptions.
Google Maps API already loaded on the page¶
- If your page already loads the Maps JavaScript API, the widget will use the existing
google.mapsobject and will not load the API a second time. - If the existing Maps load uses a different API key, both will share whichever Maps instance loaded first — this is standard Google Maps behavior.
JavaScript errors in console¶
- Ensure there are no syntax errors in your configuration object (missing quotes, trailing commas in older browsers, etc.).
- Confirm
widgets.jsis loaded fromhttps://lucit.app/embed/v1/widgets.js.