How is your experience with the OutSystems Community?
12
Views
3
Comments
[Significant Change Location Plugin] How to save a location to the database?

In the documentation I'm reading:

It is possible save the latitude and longitude of the device in various ways:

  • DataBase;
  • URL End Point;

But I can only see an example how to do it via an API. Can it be done directly?


2026-05-10 20-22-56
Rashid Al-Aamri

Hi Wouter,

Short answer: the API is the way to save to your database, and for background tracking it's the only reliable one. Here's why, and how to set it up cleanly.

Why there's no "direct" save
The tracking runs natively in the background, outside your app's OutSystems client logic, and keeps running when the app is minimized or closed. At that point no client or server action of yours can run, so the plugin sends each fix by HTTP POST to the URLs you configure. Your ODC database is only reachable from server logic, so an exposed REST API whose logic writes to an entity is the "database" option in practice. The id field in the location parameters refers to the plugin's own local store on the device, where it keeps fixes while offline before sending them to the second (batch) API.

Setup in ODC
1. Create a DeviceLocation entity: UserId, DeviceId, Latitude, Longitude (Decimal), Accuracy, Speed, Provider, RecordedOn (DateTime), plus an index on (UserId, RecordedOn).
2. In a server app, expose a REST API with two POST methods matching the plugin's PostTemplate:
  - SaveLocation (one location)
  - SaveLocations (list, used for the offline/retry batch)
3. In each method convert time (UTC milliseconds since 1970) to DateTime with AddSeconds(NewDateTime(1970,1,1,0,0,0), DecimalToInteger(time / 1000)), then CreateDeviceLocation.
4. Point the plugin's URL settings in StartTracking to those two endpoints.

Make it production-ready
- Authenticate: since the plugin lets you set and change headers at runtime, send a per-user token in a header when you call StartTracking, and validate it in the API's OnAuthentication. Without it, anyone who finds the URL can write locations.
- Deduplicate: the batch API can resend fixes that already arrived. Before inserting, skip records with the same DeviceId + RecordedOn (or add a unique index on them).
- Filter noise: ignore fixes with poor accuracy (e.g. above 100 m) and reject ones where isFromMockProvider is true on Android if location integrity matters.
- Keep it small: add a Timer that purges or aggregates old rows, because continuous tracking grows the table fast.

If you only need locations while the app is open, you can skip the plugin's sync entirely: get the position in a client action and call a server action that creates the record. But for true background tracking, the API route is the right design.

Hope this helps!

UserImage.jpg
Wouter Baeten

What do you mean with "the plugin's PostTemplate"?

2026-05-10 20-22-56
Rashid Al-Aamri

Hi Wouter, good question, I should have explained that term.

PostTemplate is a setting of the plugin itself. Step 3 of the plugin’s Forge documentation describes it as “the JSON structure sent to the API during the tracking”. You find it in the JavaScript of the plugin’s StartTracking action.

Think of it as a form the plugin fills in for every location it records: you decide the field names, and the plugin puts the real values in them. The values you can use are the ones listed in the documentation’s “Location parameter” table (latitude, longitude, time, accuracy, speed, etc.).

For example, if your template has the fields lat, lng, recordedAt and accuracy, mapped to latitude, longitude, time and accuracy, each location reaches your API as: { "lat": 23.5880, "lng": 58.3829, "recordedAt": 1760000000000, "accuracy": 12 }

So the steps are:

  1. In the plugin module, open StartTracking and find the PostTemplate in its JavaScript.
  2. Use the same field names as the request structure of your exposed REST API method (e.g. SaveLocation with Lat, Lng, RecordedAt, Accuracy). Then the data maps automatically, with no extra conversion on the server.
  3. In the API method, convert recordedAt (milliseconds since 1970, UTC) to DateTime and create the record in your entity.

Hope this makes it clearer!

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.