[{"data":1,"prerenderedAt":1977},["ShallowReactive",2],{"docs:/docs/high-level-sdks/track":3},{"id":4,"title":5,"body":6,"description":1970,"extension":1971,"meta":1972,"navigation":230,"path":1973,"seo":1974,"stem":1975,"__hash__":1976},"docs/docs/high-level-sdks/track.md","Track SDK",{"type":7,"value":8,"toc":1955},"minimark",[9,14,18,23,34,39,64,68,97,107,153,162,189,362,366,390,413,417,1234,1238,1241,1246,1406,1516,1520,1632,1635,1798,1802,1872,1876,1951],[10,11,13],"h1",{"id":12},"nolagtrack","@nolag/track",[15,16,17],"p",{},"Vehicle and asset GPS tracking with geofencing and location history.",[19,20,22],"h2",{"id":21},"overview","Overview",[15,24,25,26,29,30,33],{},"Track vehicles, delivery drivers, drones, or any moving asset in real time. ",[27,28,13],"code",{}," broadcasts location updates to zone subscribers instantly. Geofence detection runs client-side using the haversine formula for circular boundaries and a ray-casting algorithm for polygon boundaries, so triggers fire without a server round-trip. Zones group assets by geographic area or fleet. Join multiple zones to observe overlapping regions. Your app owns one core NoLag client and injects it into ",[27,31,32],{},"NoLagTrack","; the wrapper attaches its behaviour to that connection.",[35,36,38],"h3",{"id":37},"key-features","Key Features",[40,41,42,46,49,52,55,58,61],"ul",{},[43,44,45],"li",{},"Real-time GPS location broadcast to zone subscribers",[43,47,48],{},"In-memory location buffer per asset for client-side history",[43,50,51],{},"Client-side geofence detection for circle (haversine) and polygon (ray-casting)",[43,53,54],{},"Geofences narrow the server-side location filter to the grid cells they cover",[43,56,57],{},"Asset online/offline presence via lobby",[43,59,60],{},"Optional metadata attached to each location point",[43,62,63],{},"Automatic reconnect with zone and presence restoration",[19,65,67],{"id":66},"how-it-works","How It Works",[15,69,70,72,73,76,77,80,81,84,85,88,89,92,93,96],{},[27,71,32],{}," attaches to an injected ",[27,74,75],{},"@nolag/js-sdk"," client and manages a lobby that tracks which assets are online. Calling ",[27,78,79],{},"joinZone(name)"," returns a ",[27,82,83],{},"TrackingZone"," that subscribes to two topics: ",[27,86,87],{},"locations"," for GPS points and ",[27,90,91],{},"_geofence"," for geofence events published by your own services. Neither topic is logged server-side, which suits high-frequency GPS data. Location history is kept in memory on the client. Geofence evaluation happens locally on each ",[27,94,95],{},"locationUpdate",", for your own points and for remote ones.",[15,98,99,100,103,104,106],{},"Geofences also shape what a zone receives. Every location is published with a filter naming its geo-grid cell (0.01 degree squares). When you add or remove a geofence, the zone recomputes the cells its geofences cover and calls ",[27,101,102],{},"setFilters"," on the ",[27,105,87],{}," subscription, so a zone with geofences only receives location updates from those cells. With no geofences, and no filters of your own, the subscription is a wildcard and receives every update in the zone. The app owns the socket lifecycle; the wrapper never opens or closes it.",[108,109,110,123],"table",{},[111,112,113],"thead",{},[114,115,116,120],"tr",{},[117,118,119],"th",{},"Topic",[117,121,122],{},"Purpose",[124,125,126,136],"tbody",{},[114,127,128,133],{},[129,130,131],"td",{},[27,132,87],{},[129,134,135],{},"GPS location points with optional metadata, tagged with their geo-grid cell",[114,137,138,142],{},[129,139,140],{},[27,141,91],{},[129,143,144,145,148,149,152],{},"Inbound ",[27,146,147],{},"GeofenceEvent"," messages from your own services. The SDK only listens here and re-emits them as ",[27,150,151],{},"geofenceTriggered","; it never publishes to this topic",[15,154,155,156,161],{},"A fresh subscribe or an ordinary reconnect never replays history, and this SDK never triggers replay; see ",[157,158,160],"a",{"href":159},"/docs/concepts/replay","Replay"," for the one case where the broker replays messages.",[163,164,166],"callout",{"type":165},"info",[15,167,168,172,173,176,177,180,181,184,185,188],{},[169,170,171],"strong",{},"Before you start."," Create an app from the ",[27,174,175],{},"nolag-track-sdk"," blueprint. That seeds the rooms this SDK expects (",[27,178,179],{},"fleet-zone",") and the ",[27,182,183],{},"online"," lobby, and returns an app slug with a random suffix. That slug is the ",[27,186,187],{},"appName"," you pass to the wrapper. You can also do this in the portal: Apps, New App, pick the blueprint.",[190,191,192],"code-tabs",{},[193,194,200],"pre",{"className":195,"code":196,"filename":197,"language":198,"meta":199,"style":199},"language-typescript shiki shiki-themes github-light github-dark","import { NoLagApi } from \"@nolag/js-sdk\";\n\nconst api = new NoLagApi(process.env.NOLAG_API_KEY); // nlg_live_...\nconst app = await api.apps.create({ name: \"My App\", blueprintId: \"nolag-track-sdk\" });\nconsole.log(app.slug); // e.g. \"my-app-a3f9\": this is your appName\n\nconst actor = await api.actors.create({ name: \"web-client\", actorType: \"user\" });\nconsole.log(actor.accessToken); // shown once; keep it\n","Setup (server side, once)","typescript","",[27,201,202,225,232,265,299,314,319,349],{"__ignoreMap":199},[203,204,207,211,215,218,222],"span",{"class":205,"line":206},"line",1,[203,208,210],{"class":209},"szBVR","import",[203,212,214],{"class":213},"sVt8B"," { NoLagApi } ",[203,216,217],{"class":209},"from",[203,219,221],{"class":220},"sZZnC"," \"@nolag/js-sdk\"",[203,223,224],{"class":213},";\n",[203,226,228],{"class":205,"line":227},2,[203,229,231],{"emptyLinePlaceholder":230},true,"\n",[203,233,235,238,242,245,248,252,255,258,261],{"class":205,"line":234},3,[203,236,237],{"class":209},"const",[203,239,241],{"class":240},"sj4cs"," api",[203,243,244],{"class":209}," =",[203,246,247],{"class":209}," new",[203,249,251],{"class":250},"sScJk"," NoLagApi",[203,253,254],{"class":213},"(process.env.",[203,256,257],{"class":240},"NOLAG_API_KEY",[203,259,260],{"class":213},"); ",[203,262,264],{"class":263},"sJ8bj","// nlg_live_...\n",[203,266,268,270,273,275,278,281,284,287,290,293,296],{"class":205,"line":267},4,[203,269,237],{"class":209},[203,271,272],{"class":240}," app",[203,274,244],{"class":209},[203,276,277],{"class":209}," await",[203,279,280],{"class":213}," api.apps.",[203,282,283],{"class":250},"create",[203,285,286],{"class":213},"({ name: ",[203,288,289],{"class":220},"\"My App\"",[203,291,292],{"class":213},", blueprintId: ",[203,294,295],{"class":220},"\"nolag-track-sdk\"",[203,297,298],{"class":213}," });\n",[203,300,302,305,308,311],{"class":205,"line":301},5,[203,303,304],{"class":213},"console.",[203,306,307],{"class":250},"log",[203,309,310],{"class":213},"(app.slug); ",[203,312,313],{"class":263},"// e.g. \"my-app-a3f9\": this is your appName\n",[203,315,317],{"class":205,"line":316},6,[203,318,231],{"emptyLinePlaceholder":230},[203,320,322,324,327,329,331,334,336,338,341,344,347],{"class":205,"line":321},7,[203,323,237],{"class":209},[203,325,326],{"class":240}," actor",[203,328,244],{"class":209},[203,330,277],{"class":209},[203,332,333],{"class":213}," api.actors.",[203,335,283],{"class":250},[203,337,286],{"class":213},[203,339,340],{"class":220},"\"web-client\"",[203,342,343],{"class":213},", actorType: ",[203,345,346],{"class":220},"\"user\"",[203,348,298],{"class":213},[203,350,352,354,356,359],{"class":205,"line":351},8,[203,353,304],{"class":213},[203,355,307],{"class":250},[203,357,358],{"class":213},"(actor.accessToken); ",[203,360,361],{"class":263},"// shown once; keep it\n",[19,363,365],{"id":364},"installation","Installation",[190,367,368],{},[193,369,374],{"className":370,"code":371,"filename":372,"language":373,"meta":199,"style":199},"language-bash shiki shiki-themes github-light github-dark","npm install @nolag/track @nolag/js-sdk\n","Terminal","bash",[27,375,376],{"__ignoreMap":199},[203,377,378,381,384,387],{"class":205,"line":206},[203,379,380],{"class":250},"npm",[203,382,383],{"class":220}," install",[203,385,386],{"class":220}," @nolag/track",[203,388,389],{"class":220}," @nolag/js-sdk\n",[163,391,392],{"type":165},[15,393,394,397,398,400,401,404,405,408,409,412],{},[169,395,396],{},"Shared connection."," One core NoLag client can back several wrapper SDKs at once, for example asset tracking, a dashboard, and notify on a single socket, as long as each wrapper uses a distinct ",[27,399,187],{},". Each wrapper attaches its handlers on construction and releases them with ",[27,402,403],{},"detach()",", and never touches the socket itself. Your app owns ",[27,406,407],{},"connect()"," and ",[27,410,411],{},"disconnect()",".",[19,414,416],{"id":415},"quick-start","Quick Start",[190,418,419],{},[193,420,423],{"className":195,"code":421,"filename":422,"language":198,"meta":199,"style":199},"import { NoLag } from '@nolag/js-sdk'\nimport { NoLagTrack } from '@nolag/track'\n\n// The app owns one core client. In a browser, pass a token provider so the\n// SDK can mint fresh short-lived client tokens from your backend.\nconst client = NoLag(async () => (await (await fetch('/api/nolag-token')).json()).token)\n\n// Inject the client into the track wrapper\nconst tracker = new NoLagTrack({\n  client,\n  appName: APP_SLUG, // the slug returned when you created the app\n  assetId: 'drv_001',\n  assetName: 'Van 12',\n})\n\nawait client.connect()   // the app owns the connection\nawait tracker.ready()    // wrapper setup complete\n\n// Join the seeded tracking zone (groups assets by geographic area or fleet)\nconst zone = tracker.joinZone('fleet-zone')\n\n// Device side: report a location. Publishers never receive their own messages,\n// so the wrapper stores the point locally and emits `locationUpdate` itself.\nzone.sendLocation({ lat: 51.5074, lng: -0.1278, speed: 11.6 }, { driverId: 'drv_001' })\n\n// Add a circular geofence (haversine distance check)\nzone.addGeofence({\n  id: 'depot-central',\n  shape: 'circle',\n  center: { lat: 51.5074, lng: -0.1278 },\n  radiusMeters: 500,\n  name: 'Central Depot',\n})\n\n// Add a polygon geofence (ray-casting algorithm)\nzone.addGeofence({\n  id: 'zone-east',\n  shape: 'polygon',\n  points: [\n    { lat: 51.52, lng: -0.05 },\n    { lat: 51.50, lng: -0.03 },\n    { lat: 51.48, lng: -0.06 },\n    { lat: 51.50, lng: -0.09 },\n  ],\n  name: 'East Zone',\n})\n// From here on this zone only receives location updates from the grid cells\n// the two geofences cover. Remove every geofence to go back to receiving all.\n\n// Controller side: listen for updates\nzone.on('locationUpdate', ({ assetId, point, metadata, timestamp }) => {\n  console.log(`Asset ${assetId} at ${point.lat}, ${point.lng}`, metadata, timestamp)\n})\n\nzone.on('geofenceTriggered', ({ assetId, geofenceId, type, point }) => {\n  console.log(`Asset ${assetId} ${type} geofence ${geofenceId} at ${point.lat}, ${point.lng}`)\n})\n\n// Read the in-memory location history for one asset (synchronous)\nconst history = zone.getLocationHistory('drv_001')\nconsole.log(`${history.length} location points in buffer`)\n\n// Teardown: the wrapper releases its handlers; the app closes the socket.\ntracker.detach()\nclient.disconnect()\n","TypeScript",[27,424,425,437,449,453,458,463,514,518,523,541,547,562,574,585,591,596,613,630,635,641,664,669,675,681,719,724,730,740,751,762,779,790,801,806,811,817,826,836,846,852,870,887,904,920,926,936,941,947,953,958,964,1007,1048,1053,1058,1094,1137,1142,1147,1153,1175,1200,1205,1211,1223],{"__ignoreMap":199},[203,426,427,429,432,434],{"class":205,"line":206},[203,428,210],{"class":209},[203,430,431],{"class":213}," { NoLag } ",[203,433,217],{"class":209},[203,435,436],{"class":220}," '@nolag/js-sdk'\n",[203,438,439,441,444,446],{"class":205,"line":227},[203,440,210],{"class":209},[203,442,443],{"class":213}," { NoLagTrack } ",[203,445,217],{"class":209},[203,447,448],{"class":220}," '@nolag/track'\n",[203,450,451],{"class":205,"line":234},[203,452,231],{"emptyLinePlaceholder":230},[203,454,455],{"class":205,"line":267},[203,456,457],{"class":263},"// The app owns one core client. In a browser, pass a token provider so the\n",[203,459,460],{"class":205,"line":301},[203,461,462],{"class":263},"// SDK can mint fresh short-lived client tokens from your backend.\n",[203,464,465,467,470,472,475,478,481,484,487,490,493,495,497,500,502,505,508,511],{"class":205,"line":316},[203,466,237],{"class":209},[203,468,469],{"class":240}," client",[203,471,244],{"class":209},[203,473,474],{"class":250}," NoLag",[203,476,477],{"class":213},"(",[203,479,480],{"class":209},"async",[203,482,483],{"class":213}," () ",[203,485,486],{"class":209},"=>",[203,488,489],{"class":213}," (",[203,491,492],{"class":209},"await",[203,494,489],{"class":213},[203,496,492],{"class":209},[203,498,499],{"class":250}," fetch",[203,501,477],{"class":213},[203,503,504],{"class":220},"'/api/nolag-token'",[203,506,507],{"class":213},")).",[203,509,510],{"class":250},"json",[203,512,513],{"class":213},"()).token)\n",[203,515,516],{"class":205,"line":321},[203,517,231],{"emptyLinePlaceholder":230},[203,519,520],{"class":205,"line":351},[203,521,522],{"class":263},"// Inject the client into the track wrapper\n",[203,524,526,528,531,533,535,538],{"class":205,"line":525},9,[203,527,237],{"class":209},[203,529,530],{"class":240}," tracker",[203,532,244],{"class":209},[203,534,247],{"class":209},[203,536,537],{"class":250}," NoLagTrack",[203,539,540],{"class":213},"({\n",[203,542,544],{"class":205,"line":543},10,[203,545,546],{"class":213},"  client,\n",[203,548,550,553,556,559],{"class":205,"line":549},11,[203,551,552],{"class":213},"  appName: ",[203,554,555],{"class":240},"APP_SLUG",[203,557,558],{"class":213},", ",[203,560,561],{"class":263},"// the slug returned when you created the app\n",[203,563,565,568,571],{"class":205,"line":564},12,[203,566,567],{"class":213},"  assetId: ",[203,569,570],{"class":220},"'drv_001'",[203,572,573],{"class":213},",\n",[203,575,577,580,583],{"class":205,"line":576},13,[203,578,579],{"class":213},"  assetName: ",[203,581,582],{"class":220},"'Van 12'",[203,584,573],{"class":213},[203,586,588],{"class":205,"line":587},14,[203,589,590],{"class":213},"})\n",[203,592,594],{"class":205,"line":593},15,[203,595,231],{"emptyLinePlaceholder":230},[203,597,599,601,604,607,610],{"class":205,"line":598},16,[203,600,492],{"class":209},[203,602,603],{"class":213}," client.",[203,605,606],{"class":250},"connect",[203,608,609],{"class":213},"()   ",[203,611,612],{"class":263},"// the app owns the connection\n",[203,614,616,618,621,624,627],{"class":205,"line":615},17,[203,617,492],{"class":209},[203,619,620],{"class":213}," tracker.",[203,622,623],{"class":250},"ready",[203,625,626],{"class":213},"()    ",[203,628,629],{"class":263},"// wrapper setup complete\n",[203,631,633],{"class":205,"line":632},18,[203,634,231],{"emptyLinePlaceholder":230},[203,636,638],{"class":205,"line":637},19,[203,639,640],{"class":263},"// Join the seeded tracking zone (groups assets by geographic area or fleet)\n",[203,642,644,646,649,651,653,656,658,661],{"class":205,"line":643},20,[203,645,237],{"class":209},[203,647,648],{"class":240}," zone",[203,650,244],{"class":209},[203,652,620],{"class":213},[203,654,655],{"class":250},"joinZone",[203,657,477],{"class":213},[203,659,660],{"class":220},"'fleet-zone'",[203,662,663],{"class":213},")\n",[203,665,667],{"class":205,"line":666},21,[203,668,231],{"emptyLinePlaceholder":230},[203,670,672],{"class":205,"line":671},22,[203,673,674],{"class":263},"// Device side: report a location. Publishers never receive their own messages,\n",[203,676,678],{"class":205,"line":677},23,[203,679,680],{"class":263},"// so the wrapper stores the point locally and emits `locationUpdate` itself.\n",[203,682,684,687,690,693,696,699,702,705,708,711,714,716],{"class":205,"line":683},24,[203,685,686],{"class":213},"zone.",[203,688,689],{"class":250},"sendLocation",[203,691,692],{"class":213},"({ lat: ",[203,694,695],{"class":240},"51.5074",[203,697,698],{"class":213},", lng: ",[203,700,701],{"class":209},"-",[203,703,704],{"class":240},"0.1278",[203,706,707],{"class":213},", speed: ",[203,709,710],{"class":240},"11.6",[203,712,713],{"class":213}," }, { driverId: ",[203,715,570],{"class":220},[203,717,718],{"class":213}," })\n",[203,720,722],{"class":205,"line":721},25,[203,723,231],{"emptyLinePlaceholder":230},[203,725,727],{"class":205,"line":726},26,[203,728,729],{"class":263},"// Add a circular geofence (haversine distance check)\n",[203,731,733,735,738],{"class":205,"line":732},27,[203,734,686],{"class":213},[203,736,737],{"class":250},"addGeofence",[203,739,540],{"class":213},[203,741,743,746,749],{"class":205,"line":742},28,[203,744,745],{"class":213},"  id: ",[203,747,748],{"class":220},"'depot-central'",[203,750,573],{"class":213},[203,752,754,757,760],{"class":205,"line":753},29,[203,755,756],{"class":213},"  shape: ",[203,758,759],{"class":220},"'circle'",[203,761,573],{"class":213},[203,763,765,768,770,772,774,776],{"class":205,"line":764},30,[203,766,767],{"class":213},"  center: { lat: ",[203,769,695],{"class":240},[203,771,698],{"class":213},[203,773,701],{"class":209},[203,775,704],{"class":240},[203,777,778],{"class":213}," },\n",[203,780,782,785,788],{"class":205,"line":781},31,[203,783,784],{"class":213},"  radiusMeters: ",[203,786,787],{"class":240},"500",[203,789,573],{"class":213},[203,791,793,796,799],{"class":205,"line":792},32,[203,794,795],{"class":213},"  name: ",[203,797,798],{"class":220},"'Central Depot'",[203,800,573],{"class":213},[203,802,804],{"class":205,"line":803},33,[203,805,590],{"class":213},[203,807,809],{"class":205,"line":808},34,[203,810,231],{"emptyLinePlaceholder":230},[203,812,814],{"class":205,"line":813},35,[203,815,816],{"class":263},"// Add a polygon geofence (ray-casting algorithm)\n",[203,818,820,822,824],{"class":205,"line":819},36,[203,821,686],{"class":213},[203,823,737],{"class":250},[203,825,540],{"class":213},[203,827,829,831,834],{"class":205,"line":828},37,[203,830,745],{"class":213},[203,832,833],{"class":220},"'zone-east'",[203,835,573],{"class":213},[203,837,839,841,844],{"class":205,"line":838},38,[203,840,756],{"class":213},[203,842,843],{"class":220},"'polygon'",[203,845,573],{"class":213},[203,847,849],{"class":205,"line":848},39,[203,850,851],{"class":213},"  points: [\n",[203,853,855,858,861,863,865,868],{"class":205,"line":854},40,[203,856,857],{"class":213},"    { lat: ",[203,859,860],{"class":240},"51.52",[203,862,698],{"class":213},[203,864,701],{"class":209},[203,866,867],{"class":240},"0.05",[203,869,778],{"class":213},[203,871,873,875,878,880,882,885],{"class":205,"line":872},41,[203,874,857],{"class":213},[203,876,877],{"class":240},"51.50",[203,879,698],{"class":213},[203,881,701],{"class":209},[203,883,884],{"class":240},"0.03",[203,886,778],{"class":213},[203,888,890,892,895,897,899,902],{"class":205,"line":889},42,[203,891,857],{"class":213},[203,893,894],{"class":240},"51.48",[203,896,698],{"class":213},[203,898,701],{"class":209},[203,900,901],{"class":240},"0.06",[203,903,778],{"class":213},[203,905,907,909,911,913,915,918],{"class":205,"line":906},43,[203,908,857],{"class":213},[203,910,877],{"class":240},[203,912,698],{"class":213},[203,914,701],{"class":209},[203,916,917],{"class":240},"0.09",[203,919,778],{"class":213},[203,921,923],{"class":205,"line":922},44,[203,924,925],{"class":213},"  ],\n",[203,927,929,931,934],{"class":205,"line":928},45,[203,930,795],{"class":213},[203,932,933],{"class":220},"'East Zone'",[203,935,573],{"class":213},[203,937,939],{"class":205,"line":938},46,[203,940,590],{"class":213},[203,942,944],{"class":205,"line":943},47,[203,945,946],{"class":263},"// From here on this zone only receives location updates from the grid cells\n",[203,948,950],{"class":205,"line":949},48,[203,951,952],{"class":263},"// the two geofences cover. Remove every geofence to go back to receiving all.\n",[203,954,956],{"class":205,"line":955},49,[203,957,231],{"emptyLinePlaceholder":230},[203,959,961],{"class":205,"line":960},50,[203,962,963],{"class":263},"// Controller side: listen for updates\n",[203,965,967,969,972,974,977,980,984,986,989,991,994,996,999,1002,1004],{"class":205,"line":966},51,[203,968,686],{"class":213},[203,970,971],{"class":250},"on",[203,973,477],{"class":213},[203,975,976],{"class":220},"'locationUpdate'",[203,978,979],{"class":213},", ({ ",[203,981,983],{"class":982},"s4XuR","assetId",[203,985,558],{"class":213},[203,987,988],{"class":982},"point",[203,990,558],{"class":213},[203,992,993],{"class":982},"metadata",[203,995,558],{"class":213},[203,997,998],{"class":982},"timestamp",[203,1000,1001],{"class":213}," }) ",[203,1003,486],{"class":209},[203,1005,1006],{"class":213}," {\n",[203,1008,1010,1013,1015,1017,1020,1022,1025,1027,1029,1032,1035,1037,1039,1042,1045],{"class":205,"line":1009},52,[203,1011,1012],{"class":213},"  console.",[203,1014,307],{"class":250},[203,1016,477],{"class":213},[203,1018,1019],{"class":220},"`Asset ${",[203,1021,983],{"class":213},[203,1023,1024],{"class":220},"} at ${",[203,1026,988],{"class":213},[203,1028,412],{"class":220},[203,1030,1031],{"class":213},"lat",[203,1033,1034],{"class":220},"}, ${",[203,1036,988],{"class":213},[203,1038,412],{"class":220},[203,1040,1041],{"class":213},"lng",[203,1043,1044],{"class":220},"}`",[203,1046,1047],{"class":213},", metadata, timestamp)\n",[203,1049,1051],{"class":205,"line":1050},53,[203,1052,590],{"class":213},[203,1054,1056],{"class":205,"line":1055},54,[203,1057,231],{"emptyLinePlaceholder":230},[203,1059,1061,1063,1065,1067,1070,1072,1074,1076,1079,1081,1084,1086,1088,1090,1092],{"class":205,"line":1060},55,[203,1062,686],{"class":213},[203,1064,971],{"class":250},[203,1066,477],{"class":213},[203,1068,1069],{"class":220},"'geofenceTriggered'",[203,1071,979],{"class":213},[203,1073,983],{"class":982},[203,1075,558],{"class":213},[203,1077,1078],{"class":982},"geofenceId",[203,1080,558],{"class":213},[203,1082,1083],{"class":982},"type",[203,1085,558],{"class":213},[203,1087,988],{"class":982},[203,1089,1001],{"class":213},[203,1091,486],{"class":209},[203,1093,1006],{"class":213},[203,1095,1097,1099,1101,1103,1105,1107,1110,1112,1115,1117,1119,1121,1123,1125,1127,1129,1131,1133,1135],{"class":205,"line":1096},56,[203,1098,1012],{"class":213},[203,1100,307],{"class":250},[203,1102,477],{"class":213},[203,1104,1019],{"class":220},[203,1106,983],{"class":213},[203,1108,1109],{"class":220},"} ${",[203,1111,1083],{"class":213},[203,1113,1114],{"class":220},"} geofence ${",[203,1116,1078],{"class":213},[203,1118,1024],{"class":220},[203,1120,988],{"class":213},[203,1122,412],{"class":220},[203,1124,1031],{"class":213},[203,1126,1034],{"class":220},[203,1128,988],{"class":213},[203,1130,412],{"class":220},[203,1132,1041],{"class":213},[203,1134,1044],{"class":220},[203,1136,663],{"class":213},[203,1138,1140],{"class":205,"line":1139},57,[203,1141,590],{"class":213},[203,1143,1145],{"class":205,"line":1144},58,[203,1146,231],{"emptyLinePlaceholder":230},[203,1148,1150],{"class":205,"line":1149},59,[203,1151,1152],{"class":263},"// Read the in-memory location history for one asset (synchronous)\n",[203,1154,1156,1158,1161,1163,1166,1169,1171,1173],{"class":205,"line":1155},60,[203,1157,237],{"class":209},[203,1159,1160],{"class":240}," history",[203,1162,244],{"class":209},[203,1164,1165],{"class":213}," zone.",[203,1167,1168],{"class":250},"getLocationHistory",[203,1170,477],{"class":213},[203,1172,570],{"class":220},[203,1174,663],{"class":213},[203,1176,1178,1180,1182,1184,1187,1190,1192,1195,1198],{"class":205,"line":1177},61,[203,1179,304],{"class":213},[203,1181,307],{"class":250},[203,1183,477],{"class":213},[203,1185,1186],{"class":220},"`${",[203,1188,1189],{"class":213},"history",[203,1191,412],{"class":220},[203,1193,1194],{"class":240},"length",[203,1196,1197],{"class":220},"} location points in buffer`",[203,1199,663],{"class":213},[203,1201,1203],{"class":205,"line":1202},62,[203,1204,231],{"emptyLinePlaceholder":230},[203,1206,1208],{"class":205,"line":1207},63,[203,1209,1210],{"class":263},"// Teardown: the wrapper releases its handlers; the app closes the socket.\n",[203,1212,1214,1217,1220],{"class":205,"line":1213},64,[203,1215,1216],{"class":213},"tracker.",[203,1218,1219],{"class":250},"detach",[203,1221,1222],{"class":213},"()\n",[203,1224,1226,1229,1232],{"class":205,"line":1225},65,[203,1227,1228],{"class":213},"client.",[203,1230,1231],{"class":250},"disconnect",[203,1233,1222],{"class":213},[19,1235,1237],{"id":1236},"api-reference","API Reference",[35,1239,32],{"id":1240},"nolagtrack-1",[1242,1243,1245],"h4",{"id":1244},"constructor-options","Constructor Options",[108,1247,1248,1261],{},[111,1249,1250],{},[114,1251,1252,1255,1258],{},[117,1253,1254],{},"Option",[117,1256,1257],{},"Type",[117,1259,1260],{},"Description",[124,1262,1263,1281,1299,1312,1326,1340,1355,1370,1388],{},[114,1264,1265,1270,1275],{},[129,1266,1267],{},[27,1268,1269],{},"client",[129,1271,1272],{},[27,1273,1274],{},"NoLagSocket",[129,1276,1277,1280],{},[169,1278,1279],{},"Required."," The injected core NoLag client the app owns and connects.",[114,1282,1283,1287,1292],{},[129,1284,1285],{},[27,1286,187],{},[129,1288,1289],{},[27,1290,1291],{},"string",[129,1293,1294,1295,1298],{},"The app slug used as the topic prefix. Pass the suffixed slug returned when you created the app; the default ",[27,1296,1297],{},"'track'"," will not match a hosted app.",[114,1300,1301,1305,1309],{},[129,1302,1303],{},[27,1304,983],{},[129,1306,1307],{},[27,1308,1291],{},[129,1310,1311],{},"Stable identifier for this asset (auto-generated if omitted).",[114,1313,1314,1319,1323],{},[129,1315,1316],{},[27,1317,1318],{},"assetName",[129,1320,1321],{},[27,1322,1291],{},[129,1324,1325],{},"Optional human-readable name for this asset.",[114,1327,1328,1332,1337],{},[129,1329,1330],{},[27,1331,993],{},[129,1333,1334],{},[27,1335,1336],{},"Record\u003Cstring, unknown>",[129,1338,1339],{},"Optional custom data attached to asset presence.",[114,1341,1342,1347,1352],{},[129,1343,1344],{},[27,1345,1346],{},"zoneNames",[129,1348,1349],{},[27,1350,1351],{},"string[]",[129,1353,1354],{},"Tracking zones to auto-join once the wrapper is ready.",[114,1356,1357,1362,1367],{},[129,1358,1359],{},[27,1360,1361],{},"zones",[129,1363,1364],{},[27,1365,1366],{},"Geofence[]",[129,1368,1369],{},"Client-side geofences to register on every joined zone.",[114,1371,1372,1377,1382],{},[129,1373,1374],{},[27,1375,1376],{},"maxLocationHistory",[129,1378,1379],{},[27,1380,1381],{},"number",[129,1383,1384,1385,1387],{},"Max location history entries per asset (default ",[27,1386,787],{},").",[114,1389,1390,1395,1400],{},[129,1391,1392],{},[27,1393,1394],{},"debug",[129,1396,1397],{},[27,1398,1399],{},"boolean",[129,1401,1402,1403,1387],{},"Enable wrapper debug logging (default ",[27,1404,1405],{},"false",[108,1407,1408,1420],{},[111,1409,1410],{},[114,1411,1412,1415,1418],{},[117,1413,1414],{},"Method",[117,1416,1417],{},"Returns",[117,1419,1260],{},[124,1421,1422,1437,1451,1469,1483,1498],{},[114,1423,1424,1429,1434],{},[129,1425,1426],{},[27,1427,1428],{},"ready()",[129,1430,1431],{},[27,1432,1433],{},"Promise\u003Cvoid>",[129,1435,1436],{},"Resolves once wrapper setup completed. Join methods throw before this resolves.",[114,1438,1439,1443,1448],{},[129,1440,1441],{},[27,1442,403],{},[129,1444,1445],{},[27,1446,1447],{},"void",[129,1449,1450],{},"Release this wrapper's handlers and topics; terminal, never closes the socket.",[114,1452,1453,1458,1462],{},[129,1454,1455],{},[27,1456,1457],{},"joinZone(name, opts?)",[129,1459,1460],{},[27,1461,83],{},[129,1463,1464,1465,1468],{},"Subscribe to a tracking zone and return it. Synchronous; returns the existing instance if already joined. ",[27,1466,1467],{},"opts.filters"," adds location filter values of your own, unioned with the geofence cells.",[114,1470,1471,1476,1480],{},[129,1472,1473],{},[27,1474,1475],{},"leaveZone(name)",[129,1477,1478],{},[27,1479,1447],{},[129,1481,1482],{},"Unsubscribe from a zone and release its resources.",[114,1484,1485,1490,1495],{},[129,1486,1487],{},[27,1488,1489],{},"getZones()",[129,1491,1492],{},[27,1493,1494],{},"TrackingZone[]",[129,1496,1497],{},"All currently joined zones.",[114,1499,1500,1505,1510],{},[129,1501,1502],{},[27,1503,1504],{},"getOnlineAssets()",[129,1506,1507],{},[27,1508,1509],{},"TrackedAsset[]",[129,1511,1512,1513,1515],{},"Assets currently present in the ",[27,1514,183],{}," lobby.",[35,1517,1519],{"id":1518},"nolagtrack-events","NoLagTrack Events",[108,1521,1522,1534],{},[111,1523,1524],{},[114,1525,1526,1529,1532],{},[117,1527,1528],{},"Event",[117,1530,1531],{},"Payload",[117,1533,1260],{},[124,1535,1536,1549,1564,1576,1588,1603,1618],{},[114,1537,1538,1543,1546],{},[129,1539,1540],{},[27,1541,1542],{},"connected",[129,1544,1545],{},"none",[129,1547,1548],{},"Wrapper setup completed on a live connection.",[114,1550,1551,1556,1561],{},[129,1552,1553],{},[27,1554,1555],{},"disconnected",[129,1557,1558],{},[27,1559,1560],{},"reason: string",[129,1562,1563],{},"Connection closed.",[114,1565,1566,1571,1573],{},[129,1567,1568],{},[27,1569,1570],{},"reconnecting",[129,1572,1545],{},[129,1574,1575],{},"The core client is attempting to reconnect.",[114,1577,1578,1583,1585],{},[129,1579,1580],{},[27,1581,1582],{},"reconnected",[129,1584,1545],{},[129,1586,1587],{},"Connection restored after a drop; zone membership and presence are restored automatically.",[114,1589,1590,1595,1600],{},[129,1591,1592],{},[27,1593,1594],{},"error",[129,1596,1597],{},[27,1598,1599],{},"error: Error",[129,1601,1602],{},"A transport or protocol error occurred.",[114,1604,1605,1610,1615],{},[129,1606,1607],{},[27,1608,1609],{},"assetOnline",[129,1611,1612],{},[27,1613,1614],{},"asset: TrackedAsset",[129,1616,1617],{},"An asset joined the lobby.",[114,1619,1620,1625,1629],{},[129,1621,1622],{},[27,1623,1624],{},"assetOffline",[129,1626,1627],{},[27,1628,1614],{},[129,1630,1631],{},"An asset left the lobby.",[35,1633,83],{"id":1634},"trackingzone",[108,1636,1637,1647],{},[111,1638,1639],{},[114,1640,1641,1643,1645],{},[117,1642,1414],{},[117,1644,1417],{},[117,1646,1260],{},[124,1648,1649,1672,1693,1709,1723,1737,1751,1766,1780],{},[114,1650,1651,1656,1661],{},[129,1652,1653],{},[27,1654,1655],{},"sendLocation(point, metadata?, opts?)",[129,1657,1658],{},[27,1659,1660],{},"LocationUpdate",[129,1662,1663,1664,1667,1668,1671],{},"Broadcast a ",[27,1665,1666],{},"GeoPoint"," with optional metadata and return the update that was sent. Tagged with its grid cell unless ",[27,1669,1670],{},"opts.filter"," replaces it, which opts the update out of geofence routing.",[114,1673,1674,1679,1684],{},[129,1675,1676],{},[27,1677,1678],{},"getLocationHistory(assetId?)",[129,1680,1681],{},[27,1682,1683],{},"LocationUpdate[]",[129,1685,1686,1687,1689,1690,1692],{},"Read location points from the in-memory buffer (up to ",[27,1688,1376],{}," per asset). Omit ",[27,1691,983],{}," to get all assets.",[114,1694,1695,1700,1704],{},[129,1696,1697],{},[27,1698,1699],{},"addGeofence(geofence)",[129,1701,1702],{},[27,1703,1447],{},[129,1705,1706,1707,412],{},"Register a circle or polygon geofence, evaluated on every location update. Recomputes the grid-cell filter on ",[27,1708,87],{},[114,1710,1711,1716,1720],{},[129,1712,1713],{},[27,1714,1715],{},"removeGeofence(id)",[129,1717,1718],{},[27,1719,1447],{},[129,1721,1722],{},"Deregister a geofence by its ID and recompute the filter.",[114,1724,1725,1730,1734],{},[129,1726,1727],{},[27,1728,1729],{},"getGeofences()",[129,1731,1732],{},[27,1733,1366],{},[129,1735,1736],{},"All geofences registered on this zone.",[114,1738,1739,1744,1748],{},[129,1740,1741],{},[27,1742,1743],{},"getAssets()",[129,1745,1746],{},[27,1747,1509],{},[129,1749,1750],{},"Remote assets currently present in this zone.",[114,1752,1753,1758,1763],{},[129,1754,1755],{},[27,1756,1757],{},"getAsset(assetId)",[129,1759,1760],{},[27,1761,1762],{},"TrackedAsset | undefined",[129,1764,1765],{},"One remote asset by ID.",[114,1767,1768,1773,1777],{},[129,1769,1770],{},[27,1771,1772],{},"setFilters(values)",[129,1774,1775],{},[27,1776,1447],{},[129,1778,1779],{},"Replace your own location filter values. They are unioned with the geofence cells, never replace them; an empty array leaves only the geofence cells.",[114,1781,1782,1791,1795],{},[129,1783,1784,1787,1788],{},[27,1785,1786],{},"addFilters(values)"," / ",[27,1789,1790],{},"removeFilters(values)",[129,1792,1793],{},[27,1794,1447],{},[129,1796,1797],{},"Add or remove your own filter values without touching the geofence cells.",[35,1799,1801],{"id":1800},"trackingzone-events","TrackingZone Events",[108,1803,1804,1814],{},[111,1805,1806],{},[114,1807,1808,1810,1812],{},[117,1809,1528],{},[117,1811,1531],{},[117,1813,1260],{},[124,1815,1816,1829,1843,1857],{},[114,1817,1818,1822,1826],{},[129,1819,1820],{},[27,1821,95],{},[129,1823,1824],{},[27,1825,1660],{},[129,1827,1828],{},"A location point was received from another asset, or sent by this one.",[114,1830,1831,1836,1840],{},[129,1832,1833],{},[27,1834,1835],{},"assetJoined",[129,1837,1838],{},[27,1839,1614],{},[129,1841,1842],{},"An asset joined this zone.",[114,1844,1845,1850,1854],{},[129,1846,1847],{},[27,1848,1849],{},"assetLeft",[129,1851,1852],{},[27,1853,1614],{},[129,1855,1856],{},"An asset left this zone.",[114,1858,1859,1863,1867],{},[129,1860,1861],{},[27,1862,151],{},[129,1864,1865],{},[27,1866,147],{},[129,1868,1869,1870,412],{},"An asset crossed a geofence boundary. Evaluated client-side on each location update, or received on ",[27,1871,91],{},[35,1873,1875],{"id":1874},"types","Types",[108,1877,1878,1887],{},[111,1879,1880],{},[114,1881,1882,1884],{},[117,1883,1257],{},[117,1885,1886],{},"Shape",[124,1888,1889,1901,1912,1928,1939],{},[114,1890,1891,1895],{},[129,1892,1893],{},[27,1894,1666],{},[129,1896,1897,1900],{},[27,1898,1899],{},"{ lat, lng, altitude?, accuracy?, heading?, speed? }"," (degrees, metres, metres per second)",[114,1902,1903,1907],{},[129,1904,1905],{},[27,1906,1660],{},[129,1908,1909],{},[27,1910,1911],{},"{ id, assetId, point: GeoPoint, metadata?, timestamp, isReplay }",[114,1913,1914,1919],{},[129,1915,1916],{},[27,1917,1918],{},"Geofence",[129,1920,1921,1924,1925],{},[27,1922,1923],{},"{ id, shape: 'circle', center: GeoPoint, radiusMeters, name?, metadata? }"," or ",[27,1926,1927],{},"{ id, shape: 'polygon', points: GeoPoint[], name?, metadata? }",[114,1929,1930,1934],{},[129,1931,1932],{},[27,1933,147],{},[129,1935,1936],{},[27,1937,1938],{},"{ geofenceId, assetId, type: 'enter' | 'exit', point: GeoPoint, timestamp }",[114,1940,1941,1946],{},[129,1942,1943],{},[27,1944,1945],{},"TrackedAsset",[129,1947,1948],{},[27,1949,1950],{},"{ assetId, actorTokenId, assetName?, lastLocation?, metadata?, joinedAt, isLocal }",[1952,1953,1954],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":199,"searchDepth":227,"depth":227,"links":1956},[1957,1960,1961,1962,1963],{"id":21,"depth":227,"text":22,"children":1958},[1959],{"id":37,"depth":234,"text":38},{"id":66,"depth":227,"text":67},{"id":364,"depth":227,"text":365},{"id":415,"depth":227,"text":416},{"id":1236,"depth":227,"text":1237,"children":1964},[1965,1966,1967,1968,1969],{"id":1240,"depth":234,"text":32},{"id":1518,"depth":234,"text":1519},{"id":1634,"depth":234,"text":83},{"id":1800,"depth":234,"text":1801},{"id":1874,"depth":234,"text":1875},"Vehicle and asset GPS tracking with geofencing and location history. Real-time tracking for fleets, delivery drivers, drones, and any moving asset.","md",{},"/docs/high-level-sdks/track",{"title":5,"description":1970},"docs/high-level-sdks/track","jCnBHkBXL0bN7wh9OYzzLjjy81OzIo0O7Ke2OxqWLlo",1789869420710]