Appearance
πΊοΈ Zubie Web Component β
Designed for quick integration and a seamless user experience, the Zubie web component allows a map view of Zubie vehicle trip history to be embedded directly into partner applications. It handles the fetching, parsing, and visualization of trip data, removing the need to build complex data visualizations from scratch.
The component is a simple HTML element (<zubie-trips-map>) that can be placed anywhere in your application. It includes an interactive or static map, renders trip routes, and displays key event information like trip start and end points.

π Getting Started β
Follow these steps to get the component up and running in your application.
β Requirements β
To use the web component, you will need the following:
- Zinc App
- Web Component Authentication Token
- Mapbox Access Token
- Web Component File
Zinc App β
You will need a Zinc Application Client ID and Client Secret in order for users to authorize your application to access their Zubie account data.
You can create a free developer account for building and testing your integration at https://developer.zubie.com/manage-apps.
Web Component Authentication Token β
To display trip data, the component must be authenticated for a specific Zubie account. This is typically the account of your application's end-user. Your application will be responsible for obtaining an authentication token for the user's account and passing it to the web component.
An authentication token is required to authorize access to a Zubie user's data. This token should be securely obtained by your application and passed into the zubie-token attribute. If the token is missing or invalid, the map will not load any trip data, and an auth-error event will be emitted.
See Authentication for more information.
Mapbox Access Token β
Mapbox is the map provider used by the component. You must use your own Mapbox public access token to load the map. This token is passed into the mapbox-access-token attribute. For more information, see the Mapbox documentation on creating public tokens.
Web Component File β
Download a copy of the web component file (zubie-web-components.umd.js) from https://github.com/zubie/zubie_sdk/tree/main/web-components. Save the file in your project directory to be referenced in the HTML <script> tag.
π¦ Installation β
Insert the <script> tag into the <head> of your HTML template, pointing to the location of the component's JavaScript module. Then, insert the component tag where you want the map to render.
src attribute will need to contain the correct path to the web component file you've downloaded from Github E.g. {PATH_TO_FILE_DIRECTORY}/zubie-trips-map.umd.js.html
<html>
<head>
<script type="module" src="/dist/zubie-trips-map.umd.js"></script>
</head>
<body>
<zubie-trips-map
mapbox-access-token="mapboxtoken123"
map-type="interactive"
vehicle-key="vehiclekey123"
zubie-token="exampleauthtoken">
</zubie-trips-map>
</body>
</html>π Authentication β
The web components require JSON Web Tokens (JWT) provided by Zubie to work.
IMPORTANT These JWTs provide specific access to the data needed for this purpose and are different from the access tokens granted Zubie's normal OAuth 2.0 flows.β Prerequisites β
- You must have a Zinc app and its associated
client_idandclient_secret(the Zinc client credentials). - Your Zinc app must have been granted access through OAuth 2.0 to the account whose data the component will display and you must have the access token returned by that OAuth exchange (the OAuth token).
When provided together, these data show:
- You are authorized to act on behalf of the Zinc client
- The Zubie customer whose data you will display has granted you to it.
β οΈ Authorization Requests β
To request an authentication token that can be used by a web component, submit a POST request to:
http
https://login.zubiecar.com/api/special-purpose/v1/tokenThe following header is required:
http
Authorization: bearer {OAuth token}Where OAuth token is the token returned to your Zinc app's callback URL after the account in question granted you access to their data. Including this token demonstrates that you should have access to the account's data. See our OAuth2 guide for more information.
The body of the request must include the following data:
| Property | Description |
|---|---|
client_id | Your Zinc app's client_id |
client_secret | Your Zinc app's client_secret (providing this demonstrates your authorization to use that Zinc app) |
sub | Identification of the subject of the token (always a vehicle at this point) in the form of vehicle:[vehicle key], where "[vehicle key]" is the unique key identifier for the vehicle (available from our normal Zinc APIs and webhooks) |
aud | The origin where the web component is included, e.g., https://zubie.com You must use HTTPS |
roles | Which component you are using, currently always zubie://<zubie-trips-map /> |
scope | One of the allowed scopes from the list below |
Allowed sub format β
vehicle:[vehicle key]
Allowed roles β
zubie://<zubie-trips-map />(a verbatim string)
Allowed scope β
loc-past: All past location dataloc-past-gte:[timestamp]: Past location data more recent than or equal to the ISO 8601 timestamp (GMT assumed unless otherwise specifed)loc-past-lt:[timestamp]: Past location data older than the ISO 8601 timestamp
started-after or started-before attributes.Sample request curl
http
curl --request POST \
--url https://login.zubiecar.com/api/special-purpose/v1/token \
--header 'Authorization: Bearer ...' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "GAA4FCB7DC85660B6D32",
"client_secret": "7GQyreSH8QfnkuejLETh435raQpigWvv",
"sub": "vehicle:agpzfnp1YmllY2FycjcLEjdBY2NvpW50IhZ1SmF0Wmp1NHlZd9FVbnh0TFIyB3RLDAsSA0NhciILVVgzZmdCNUZEVVoM",
"aud": "https://zubie.com",
"roles": "zubie://<zubie-trips-map />",
"scope": "loc-past"
}'Sample response 200
json
{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik5JTjlqZkVZdFR0Rzg5RGJzSVI0MkVERE1IcGFIUS1YbXdUQmp1cjZMaVUiLCJqa3UiOiJodHRwOi8vbG9jYWxob3N0OjMwMDEvLndlbGwta25vd24vandrcy5qc29uIn0.eyJzdWIiOiJ2ZWhpY2xlOmFncHpmbnAxWW1sbExYRmhjamNMRWdkQlkyTnZkVzUwSWhad2JsTTNhbTg0UW1OMWNXczBjV3BSWlVaVVdIbEVEQXNTQTBOaGNpSUxkelY2ZEdkTGIySkRWRzhNIiwiYXVkIjoiaHR0cHM6Ly9nb29nbGUuY29tIiwiY2xpZW50X2lkIjoiQkY4NjI2NzcxRkI1QzhEQ0I5MzUiLCJzY29wZSI6ImxvYy1wYXN0Iiwicm9sZXMiOiJ6dWJpZTovLzx6dWJpZS10cmlwcy1tYXAgLz4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDEiLCJqdGkiOiIzYWUxOTA4Mi1hNzI5LTQ2YTItYTM0ZS1mN2E0MmIzOGU1ODEiLCJpYXQiOjE3NTMzMDM3NzIsImV4cCI6MTc1MzMwNzM3Mn0.hN9zdMzJiaTYSb2kkNL-8lx_40fwE3-c8q_rtMCcg8fvdlXBS8TmFnTydG1KCKhcrjD20edufS1vqPpBCRCrKGhRmgtRvvAUsm7J_AzgFOfOwOWbUULIQjDWHA6lSpAE6OuCzg_vsT3cAjwFSIWrvd57mtTVeV2hvoZTJ6zE6VPvw7My6uTx70s3PsU5kJ73wGokH9sudVUddbR-XrtCeX8Ox4WvL05hv0h6dW5WTYebVtThQwD6jpxt4hpWbxm-xsIOH6fpKf7RGB5O5KFUFQ9HkcnnCiFisjFtsqjpqZ9IU9ld2u4YZr6CNN-meQL7l--IiyPBzmQGV6QMsP2lFw",
"expires_in": 3600,
"token_type": "Bearer"
} zubie-token component property will need to be updated.Error responses β
| HTTP Status | Error Message | Description |
|---|---|---|
| 400 | Missing client credentials | You must include the client_id and client_secret in the request body |
| 400 | Missing auth token | You must include an Authentication header with a bearer token |
| 400 | Missing required claims | You must include aud, roles, scope, and sub in the request body |
| 400 | Invalid aud | The aud value does not appear to be a URL or does not use HTTPS |
| 400 | Invalid roles | The roles value must exactly match one of the options provided above |
| 400 | Invalid sub | The sub value is incorrectly formatted |
| 400 | Invalid scope | The scope value must only include options in the format specified above |
| 401 | Invalid client credentials | The included client_id or client_secret is incorrect |
| 401 | Invalid token | The token used in the Authorization header has at least one of these problems:
|
βοΈ Attributes β
Note: The component can render data in one of two ways:
- For a single trip, use both the
trip-keyandvehicle-keyattributes. - For multiple trips for a single vehicle (within a time range), use the vehicle-key attribute.
You must always provide a vehicle-key to this component.
A Zubie authentication token scoped to a specific vehicle (see Authentication) is required to authorize access to trip and vehicle data. This token must be securely obtained by your application and passed into the component. IMPORTANT This is NOT the same as the OAuth2 access_token specified in Zubie's regular OAuth2 authentication flow.
| Attribute | Value | Required | Default | Description |
|---|---|---|---|---|
mapbox-access-token | string | β | -- | A valid Mapbox access token used to authenticate map rendering. This is required for the component to load and display the map. |
zubie-token | string | β | -- | The authentication token specified in the Authentication section. IMPORTANT This is NOT the same as the OAuth2 access_token specified in Zubie's regular OAuth2 tutorial/authentication flow. |
vehicle-key | string | β | -- | Specifies the vehicle from which to load trips. The vehicle-key must match the vehicle authorized by the provided token, or the request will be rejected. You can use the optional time filters (started-after, started-before) to control which trips are rendered for the vehicle. |
trip-key | string | optional | -- | Renders a single trip by its unique trip identifier. If present, it takes priority over vehicle-key, and any time-based filters (started-after, started-before) are ignored. |
started-after | ISO 8601 datetime | optional | -- | This will be ignored if a trip-key is provided. Filters trips that started after this timestamp up to the end of the day. If started-before is also provided, both will be used as long as the time window remains within the same calendar day. If started-before exceeds midnight of the same day, it will be ignored. |
started-before | ISO 8601 datetime | optional | -- | This will be ignored if a trip-key is provided. Filters trips that started before this timestamp back to the beginning of the day. If started-after is also provided, both will be used as long as the time window remains within the same calendar day. If started-before exceeds midnight of the same day, it will be ignored. |
map-type | string | optional | "interactive" | Determines the map rendering mode. Possible values: interactive, staticinteractive renders the interactive map, allowing panning, zooming, and interaction.static renders a fixed image-based map with no interactivity. |
map-style | string | optional | "mapbox://styles/mapbox/standard" | Sets the visual style of the interactive Mapbox map. Accepts any valid Mapbox style URL. This attribute only applies when map-type is interactive and is ignored in static mode. |
default-center | string | optional | "-98.5795,39.828175" (center of US) | Fallback map center when trip data is unavailable, in "longitude,latitude" format (no brackets). Defaults to the geographic center of the contiguous United States. |
default-zoom | number | optional | 3 | Fallback zoom level used when data is still loading or is otherwise unavailable. For valid values, see Mapbox zoom levels. |
reverse-geocode | boolean | optional | false | Enables reverse geocoding using Mapboxβs Geocoding API to show a human-readable address in the Trip Stop popup. Disabled by default to avoid additional API usage. You can also define your own reverse geocoding service by setting the reverseGeocodeHandler property. See advanced usage for more details. |
π Events β
The component emits custom events to report on its lifecycle and state changes. More information on the Event interface can be found at: https://developer.mozilla.org/en-US/docs/Web/API/Event
| Event Name | Fired when⦠| event.detail | Cancelable | Bubbles |
|---|---|---|---|---|
mount | The component has mounted. | The component | β | β |
unmount | The component has unmounted. | The component | β | β |
map-load | The Mapbox map is fully initialized and visible. | Mapbox Map instance | β | β |
trip-loading | Trip data has started/finished loading. | true if loading started, false if loading ended | β | β |
api-error | An error occurs when retrieving trip data. | Error | β | β |
auth-error | Token is rejected while retrieving trip data. | Error | β | β |
trip-render | Token is rejected while retrieving trip data. | Mapbox Map instance | β | β |
error | An error occurs in the component or bubbled from the Map instance. | Error | β | β |
address-not-found | A reverse geocoded address is not found or is otherwise unavailable. (Only if reverse-geocode attribute is used and using the default reverse geocode handler). | { "message": "<error message>", "latitude": <latitude>, "longitude": <longitude>, } | β | β |
π Listening to Events β
You can add event listeners to the component just like any other HTML element.
javascript
const zubieMap = document.querySelector('zubie-trips-map');
if (zubieMap) {
// Fired when trip data has finished rendering on the map
zubieMap.addEventListener('trip-render', (event) => {
console.log('Trip has been rendered!', event.detail); // event.detail is the Mapbox Map instance
});
// Fired when a data loading error occurs
zubieMap.addEventListener('error', (event) => {
console.error('An error occurred:', event.detail); // event.detail is an Error object
// You could show a fallback UI message to the user here
});
}π§ββοΈ Advanced Usage β
π Custom Reverse Geocoding β
If you prefer to use a different geocoding service instead of the default Mapbox API, you can provide your own by setting the reverseGeocodeHandler property on the component element.
Your handler function will receive the longitude and latitude and must return a Promise that resolves to an object with the following structure:
typescript
{
street: string;
city: string;
state: string;
}For example:
javascript
// Custom reverse geocoding handler
document.getElementById('zubieTripsMap').reverseGeocodeHandler = async (
longitude,
latitude
) => {
console.log('Reverse geocoding:', longitude, latitude);
// Perform your reverse geocoding logic here.
const address = await new Promise((resolve) =>
setTimeout(() => {
// Mock address data (for demo purposes) in proper format
const mockAddress = {
street: 'Name Street',
city: 'A City',
state: 'Some State',
};
resolve(mockAddress);
}, 1000)
);
return address;
};
