Functions
Functions are bite-sized pieces of Python code that you package as a zip, upload via the Samsara dashboard, and invoke through various triggers — manually, via the API, on a schedule, or from alert workflows. Samsara handles the heavy lifting of running your code in a managed serverless runtime, so you can automate workflows, process data, and integrate with external systems without hosting your own infrastructure.
Common use cases include:
- Proof-of-concept automations and customer-specific workflows
- Alert-driven pipelines (media retrieval, scheduled analysis, notifications)
- Nightly syncs and reports
- Lightweight transformations to third-party services
Functions are available in all Samsara cloud regions. Use the regional API base URL that matches your dashboard (cloud.samsara.com, cloud.eu.samsara.com, or cloud.ca.samsara.com) when calling the Samsara REST API.
Quick start
The golden path is: Write → Bundle → Run → Observe. Write a simple Python handler, zip it, upload it, trigger a run, and read the logs. Iterate in small steps.
Ready-to-use templates in the functions-examples repository can get you up to speed quicker:
- Basic examples (dependencies, secrets, storage): basic/
- PPE detection — multi-trigger pipeline with vendored dependencies: advanced/ppe-detection
- Painting preview — alert enqueue + scheduled processing: advanced/painting-preview
If you just want to try Functions without setting up developer tooling, use the GitHub Importer with default settings, accessible from the Function editor in the dashboard.
1. Write
Create a small Python file and define your entrypoint:
def main(event, _):
...- Read inputs from
event— a flat dictionary of strings. Parse to the types you need and validate. - Don't rely on return values — production ignores them. Prefer clear, structured logs and side effects (HTTP calls, storage writes).
- Retrieve secrets at runtime (see Secrets below).
2. Bundle
Save your files into a folder (for example, a src/ directory) and create a zip (≤ 50 MB compressed). On macOS, right-click the folder in Finder and choose Compress; on Windows use Send to → Compressed (zipped) folder. Prefer a CLI? samsara-fn bundle ./src ./dist creates a ready-to-upload zip (see Local development).
If you need extra Python dependencies, vendor them into the zip (see Provided dependencies).
3. Configure and upload
In the Samsara dashboard, go to Settings → Developer → Functions and create or edit a Function:
- Set Name, Description, and Visibility. Names are unique, up to 35 characters, and cannot be changed later.
- Add Event parameters — these become keys in
event. - Add Secrets — values are stored only in the dashboard.
- Upload your zip and set the Handler as
module.function(for example,entrypoint.mainwhen your file isentrypoint.pywithdef main). - Optionally enable a Schedule.
Permissions: Users with Standard Admin or Full Admin roles have read/write access to Functions. Read-only Admin users have read access. Other users can be granted access through a custom role permission.
4. Run and observe
- Manual: In the editor tab, set an Event parameter override and trigger a run.
- API: Invoke with your regional host and a token with the
Functions > Writescope:
curl --location 'https://api.samsara.com/functions/<your-function-name>/runs' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer samsara_api_xxx' \
--data '{"paramsOverride": {}}'{ "data": { "correlationId": "084890b1-9c8a-4ba8-bee4-ec7c47b97199" } }- Alerts: In Alerts (Workflows) → Actions → Execute Function, choose your Function.
- Schedule: Enable and configure in the editor.
- Observe: Editor → Logs. Log the correlation ID (
event["SamsaraFunctionCorrelationId"]) to tie runs to logs.
Handler contract and event shape
Every invocation receives an event object (a flat Python dictionary of strings) as the first argument to your handler. The event always includes:
SamsaraFunctionTriggerSource— how the run was triggered (manual,api,schedule, oralert)SamsaraFunctionCorrelationId— a unique ID for the run; log it to find the run in logs instantly
Trigger-specific fields:
| Trigger | Event contents |
|---|---|
| Manual / API | Your configured parameters + any overrides you provide |
| Schedule | Your configured parameters + SamsaraFunctionTriggerSource="schedule" |
| Alert | Your configured parameters + assetId or driverId (one of them blank, depending on the alert trigger), alertIncidentTime, alertConfigurationId |
Example event for an alert-triggered run:
{
"SamsaraFunctionTriggerSource": "alert",
"SamsaraFunctionCorrelationId": "0a793932-3d3e-4c5c-bff7-c27bed462b9e",
"assetId": "123214",
"driverId": "",
"alertConfigurationId": "407a985a-6784-4a16-8489-2e0480100c46",
"alertIncidentTime": "1758119598619"
}Branch on the trigger source when one Function serves multiple triggers:
def main(event, _):
trigger_source = event["SamsaraFunctionTriggerSource"]
if trigger_source == "alert":
vehicle_id = event["assetId"]
# alert-specific work
if trigger_source == "schedule":
# scheduled work
...Parameters and secrets
Parameters
Treat the event like a small envelope of strings — describe what you need in the editor, then override values when testing.
- Define parameters in the editor under Event parameters. Parameter names must be unique.
- Override per run in the editor (Event parameter override) or via the API
paramsOverride. Overrides apply to that run only and do not persist.
Secrets
Secrets are for credentials and keys you don't want in code — API tokens, passwords, provider keys. Configure them once in the editor; retrieve them at runtime as a dictionary.
- Configure in Editor → Secrets. Values live only in the dashboard; after saving, only key names can be viewed outside the Function runtime.
- Secrets are encrypted and scoped to your organization and Function.
Minimal example, part of basic/just-secrets:
from samsarafnsecrets import get_secrets
def main(_, __):
secrets = get_secrets()
print({"secretsCount": len(secrets)})Using a secret with a third-party client, part of advanced/ppe-detection:
from samsarafnsecrets import get_secrets
client = openai.OpenAI(api_key=get_secrets()["OPENAI_KEY"])Practical notes:
- Store provider keys with clear names (for example,
SAMSARA_KEY,OPENAI_KEY) and reference exact keys. - Never log plaintext secret values; only send them over HTTPS.
- Never store secrets in Storage. If you encrypt artifacts before saving them to Storage, keep the encryption keys in Secrets.
Storage
Most pipelines need a place to put artifacts or a small amount of state. Functions provide three storage options:
| Storage | Use for |
|---|---|
| File storage (S3-backed) | Blobs and artifacts: images, CSVs, reports |
| Key-value database | Lightweight state: checkpoints, pipeline stages |
Temporary runtime storage (/tmp) | Scratch files during a single invocation — not persisted across runs |
File storage
Use the storage helper to put/get/list/delete binary content, part of basic/persistent-storage:
from samsarafnstorage import get_storage
storage = get_storage()
storage.put(Key="test.csv", Body=b"col1,col2\nvalue1,value2")
blob = storage.get_body(Key="test.csv")
for key in storage.list_keys(Prefix=""):
print(key)
storage.delete(Key="test.csv")You can also manage files from the Storage tab in the dashboard.
Key-value database
A namespaced wrapper over storage for lightweight state, also part of basic/persistent-storage:
from samsarafnstorage import get_database
db = get_database("my-feature")
db.put("unique-id", "123")
db.put_dict("other-unique-id", {"name": "object", "tags": ["descriptive"]})
print(db.get("unique-id"))
print(db.get_dict("other-unique-id"))
print(db.keys())
db.delete("unique-id")Temporary runtime storage
Scratch space during a single invocation, part of basic/temporary-runtime-storage:
from samsarafntempstorage import temp_storage_path
tmp = temp_storage_path()
f = tmp / "my.csv"
f.write_text("name,age\nJohn,25\nJane,30\n")Storage guidance
- Prefer small, incremental writes; avoid tight loops waiting on large downloads.
- Key prefixes follow S3 semantics — use
/in keys to mimic folders. - Namespace keys clearly; use the database wrapper for pipeline stages.
- Never store secrets in Storage. For sensitive artifacts, encrypt on write and keep keys in Secrets.
Direct AWS access
If you prefer the REST API or boto3 directly instead of the helpers:
- The storage bucket accessible at runtime is set in the environment variable
SamsaraFunctionStorageName. - The runtime is allowed to execute
s3:GetObject,s3:ListBucket,s3:PutObject, ands3:DeleteObject. - Privileged access to secrets and storage is facilitated through role chaining: call STS
assume_rolewith the role inSamsaraFunctionExecRoleArn, then pass the returned credentials to your AWS client. See basic/persistent-storage for a complete example:
def get_credentials(force_refresh=False) -> dict[str, str]:
global _credentials
if _credentials is not None and not force_refresh:
return _credentials
sts = boto3.client("sts")
res = sts.assume_role(
RoleArn=os.environ["SamsaraFunctionExecRoleArn"],
RoleSessionName=os.environ["SamsaraFunctionName"],
)
_credentials = {
"aws_access_key_id": res["Credentials"]["AccessKeyId"],
"aws_secret_access_key": res["Credentials"]["SecretAccessKey"],
"aws_session_token": res["Credentials"]["SessionToken"],
}
return _credentialsTriggers
Functions run in four ways. The event always includes SamsaraFunctionTriggerSource so you can tell which path you're in. Start with manual or API runs for validation, then wire up schedules or alerts when the behavior is ready.
| Trigger | Description |
|---|---|
| Manual | Run from the Function editor with per-run parameter overrides. Best for testing. |
| API | Programmatic invocation — best for external systems and scripts. Requires a token with the Functions > Write scope. |
| Schedule | Simple cadences (for example, daily or weekly) at specific times of day, configured in the editor. |
| Alert | Configure the Execute Function action in Alerts (Workflows). The Function must be visible to customer users to appear as an alert action. |
API example (EU region):
curl --location 'https://api.eu.samsara.com/functions/status-triggerer/runs' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer samsara_api_xxx' \
--data '{"paramsOverride": {}}'The response includes a correlationId — the same value your handler receives as event["SamsaraFunctionCorrelationId"].
Runtime environment and limits
| Property | Value |
|---|---|
| Runtime | Python 3.12, x86_64 |
| Packaging | Zip only, ≤ 50 MB compressed |
| Memory | 1,769 MB (~1 vCPU) |
| Timeout | 15 minutes |
Temporary storage (/tmp) | 512 MB |
| Invocation model | Asynchronous; no automatic retries |
| Log retention | 90 days |
Framework-provided environment variables available at runtime:
SamsaraFunctionExecRoleArnSamsaraFunctionSecretsPathSamsaraFunctionStorageNameSamsaraFunctionNameSamsaraFunctionOrgIdSamsaraFunctionCodePathSamsaraFunctionTempStoragePath
Behavioral constraints:
- Custom environment variables are not supported — pass data via event parameters or Storage.
- Custom Lambda layers are not supported — one platform-managed layer provides curated dependencies; vendor anything else into your zip.
- Handler naming follows AWS Lambda conventions (
module.function). - When a Function is visible to customer users, it runs with reserved concurrency of 1 per organization — plan for queuing in high-throughput alert scenarios.
Provided dependencies
The runtime provides a curated set of dependencies out of the box. Notable ones:
| Package | Use for |
|---|---|
samsara-api | Official SDK for the Samsara REST API |
requests | HTTP client for REST calls; pairs well with secrets for auth headers |
aiohttp | Async HTTP client/server for concurrent I/O |
pillow (PIL) | Image processing (resize, encode/decode) |
lxml | Robust XML/HTML parsing |
paramiko | SSH/SFTP for secure file transfers |
cryptography | Sign/verify or encrypt/decrypt payloads |
geopy | Geocoding and geodesy helpers |
pytz | Timezone conversions for scheduled workflows |
zeep | SOAP client for legacy enterprise integrations |
tenacity | Explicit, bounded retry logic for outbound calls |
requests-toolbelt | Multipart uploads and advanced requests use cases |
Run samsara-fn dependencies latest for the authoritative, full set with pinned versions.
For anything not in the curated set, vendor the dependency into your zip and add it to sys.path, as shown in basic/additional-python-dependencies:
from samsarafndeps import setup_additional_dependency_path
setup_additional_dependency_path("lib")
import cowsayWhen calling the Samsara API, prefer the Samsara Python SDK (samsara-api, provided in the runtime) over hand-written HTTP requests.
Observability
Executions tab
The Executions tab in the dashboard visualizes run events — starts, successes, errors, and timeouts. You can inspect the duration of a run, the parameters used to invoke it, and the handler's return value.
A Function reports an error only if the runtime throws an exception. The return value is irrelevant in this context.
Alert notifications on Function runs
For push notifications on Function runs, configure an alert. A single configuration can trigger a notification (for example, an email) for a set of Functions and events: starts, successes, errors, and timeouts.
Logs
- Logs are retained for 90 days and can be requested in batches.
- Navigate to Editor → Logs. Use Refresh to Latest Hour, fuzzy search for terms or the correlation ID, or Download as JSON to filter locally.
- Include the correlation ID in your messages to trace runs. The Lambda-defined
RequestIdis different fromSamsaraFunctionCorrelationId— prefer the latter. - Avoid logging secrets or sensitive payloads.
Minimal logging pattern:
def main(event, _):
corr_id = event["SamsaraFunctionCorrelationId"]
print(corr_id, "Function started")
# ... work ...
result = {}
print(corr_id, "Function finished", result)For structured JSON logs with log levels, see basic/correlation-logging:
from samsarafnlogs import setup_logger_once, log
def main(params, _):
setup_logger_once(params)
log("Whoops!", level="error")Local development with samsara-fn
samsara-fnThe optional samsara-fn CLI simulator gives you a tight local loop: bundle quickly, run a trigger locally, and inspect output without touching production. It mirrors the production event shape and stubs key AWS calls (sts.assume_role, ssm.get_parameter, and the S3 object operations). Third-party HTTP calls still execute normally unless you stub them.
Install into a virtual environment:
python3 -m venv venv
source venv/bin/activate # Mac/Linux
# .\venv\Scripts\Activate.ps1 # Windows PowerShell
pip install samsara-fnCommon commands:
| Command | Purpose |
|---|---|
samsara-fn --help | Overview of capabilities and subcommands |
samsara-fn templates just-secrets <dir> | Copy a minimal secrets example |
samsara-fn bundle ./src ./dist | Package a zip; review warnings; use --ignore-file if needed |
samsara-fn init <name> --zipFile ./dist/src.zip --handler entrypoint.main --parameters params.json --secrets .secret.json | Seed a local project |
samsara-fn run manual|api|schedule|alertAction | Simulate triggers; prints return values for debugging |
samsara-fn schemas | List JSON schemas for config validation |
samsara-fn dependencies latest --install | Install the curated runtime dependencies locally |
Note: the simulator uses alertAction as the run mode name; production uses alert as the trigger source value.
A practical local flow:
- Start from the
just-secretstemplate to validate secrets retrieval. - Bundle into a zip and review warnings.
- Initialize the Function locally.
- Run locally (for example,
samsara-fn run manual) to confirm parameter parsing and logging. - Align dependency expectations with
samsara-fn dependencies latestwhen vendoring dependencies.
The dashboard has a Show help? panel on every Functions tab with CLI setup steps.
Best practices
Do:
- Finish well under 15 minutes; measure and budget time. Split multi-step pipelines across triggers (for example, enqueue on alert, process on schedule).
- Make handlers idempotent — safe to re-invoke. Checkpoint progress with Storage or the key-value database.
- Log the correlation ID early and on completion.
- Use HTTPS for third-party calls; handle non-200 responses.
- Retrieve secrets at runtime; keep them out of code and event parameters.
- Vendor extra Python dependencies in the zip; pin versions in a
requirements.txtused by your vendoring script. - Namespace Storage/DB keys clearly; clean up temporary artifacts.
- Validate via manual or API runs and confirm logs before enabling alerts or schedules broadly.
- Document required parameters and secret keys in your Function's description or README.
Don't:
- Log plaintext secrets or store secrets in Storage.
- Assume retries — there are none. Design for re-invocation instead.
- Rely on return values; log outcomes instead.
- Exceed the 50 MB zip limit; avoid bundling unused files.
- Block on long polls without limits; avoid unbounded loops and sleeps.
- Depend on custom environment variables or custom Lambda layers (unsupported).
Troubleshooting
| Symptom | What to check |
|---|---|
| Function fails immediately | Logs for stack traces; handler path matches module.function; missing secrets |
| No logs visible | Narrow the time range; confirm the run completed; search by correlation ID |
| Timeout after 15 minutes | Optimize loops or batch work; split into smaller jobs across triggers |
| Cannot use as alert action | Function visibility must allow customer access |
| API calls fail | Correct regional base URL; token scopes (Functions > Write to trigger runs) |
For additional help:
- Customers: Samsara Support
- Technology partners: Partner Support
FAQ
Are languages other than Python supported?
Only Python (3.12) is supported today for Function code packages.
Can I run the same Function code in multiple regions?
Functions are deployed per organization in that organization's cloud region. If you operate in multiple regions, create and deploy Functions separately in each region's dashboard, and point API calls at the matching regional base URL.
How is this different from a Marketplace app or API token integration?
Marketplace apps use OAuth for customer installs and are suited for productized partner integrations. Functions are for custom code that runs inside Samsara — ideal for automations, single-org workflows, and rapid prototyping that calls the same APIs you would use from an external service.
