Osano Pulumi Provider for Python
⚠️ Unofficial community provider
This package is not affiliated with Osano or Pulumi. It is maintained by the community and provided "as is" under the MIT license. Use GitHub Issues for support.
pulumi-osano is the Python SDK for the Osano Pulumi provider, imported as pulumi_osano. It lets you manage Osano Cookie Consent and Unified Consent workflows alongside the rest of your infrastructure-as-code. You can:
- Create Cookie Consent configurations and rules, publish them after all dependencies settle, and export the hosted CMP script URL and exact HTML tag, so the same pipeline that provisions a website can put the consent script first in its
<head>. - Look up the script, publish status, rules, discoveries, and audit log of any Cookie Consent configuration with
get_cookie_consent_config,get_cookie_consent_configs,get_cookie_consent_rules,get_cookie_consent_discoveries, andget_cookie_consent_audit_log, for example to consume a centrally managed configuration from a website stack or to gate a switch to production mode. - Submit consent decisions programmatically from Pulumi deployments, including Global Privacy Control consents.
- Query unified consent state for a subject with
get_unified_consent, and resolve verified, anonymous, and session references withget_subject,get_subject_profile, andget_session. - Inspect UC configuration and privacy protocol collections with
get_config,get_collections, andget_collection, and check for existing consent state and hashed consent profiles withcheck_consentandget_consent_profile. - Start and verify subject-profile challenges with
send_subject_codeandverify_subject_code. Pulumi runs functions on every preview, update, and refresh, so call these two from automation rather than declaring them in a long-lived stack; otherwise each run sends a new code.
Every function also has an _output form, such as get_cookie_consent_config_output, that accepts and returns Pulumi outputs. SDKs for Node.js, Go, .NET, and Java are also available; see the project README.
Prerequisites
- Pulumi CLI v3+
- Python 3.10+
- API access to an Osano tenant: a Customer REST API key for Cookie Consent, a Unified Consent API key for Unified Consent, or both for mixed workloads
Installation
pip install pulumi-osano
In a project created with pulumi new python, add pulumi-osano to requirements.txt and run pulumi install instead.
The package declares its provider plugin, and Pulumi downloads the matching pulumi-resource-osano release from GitHub the first time you run pulumi preview or pulumi up. To install it manually, pin the version and point Pulumi at the GitHub releases:
pulumi plugin install resource osano 0.2.1 --server github://api.github.com/jflavan/pulumi-osano
Package publishing describes how each release is built and how to verify its provenance.
Quick start: publish a consent script
This program creates a Cookie Consent configuration with one rule, publishes it, and hands the script tag to the rest of the program. It assumes a project created with pulumi new python:
echo "pulumi-osano" >> requirements.txt
pulumi install
pulumi config set osano:osanoApiKey --secret # Customer REST API key
pulumi up
__main__.py:
import hashlib
import json
import pulumi
import pulumi_osano as osano
name = "www-example-com"
domains = ["www.example.com"]
mode = "permissive"
configuration = {"storagePolicyHref": "https://www.example.com/privacy"}
rule_definitions = [
{"store_type": "cookies", "classification": "ANALYTICS", "rule": "_ga", "rule_type": "EXACT_MATCH"},
]
config = osano.CookieConsentConfig(
"consent", name=name, domains=domains, mode=mode, configuration=configuration)
rules = [
osano.CookieConsentRule(
f"rule-{i}",
config_id=config.config_id,
store_type=rule["store_type"],
classification=rule["classification"],
rule=rule["rule"],
rule_type=rule["rule_type"],
)
for i, rule in enumerate(rule_definitions)
]
# Publish exactly once per change: derive the token from everything that is published.
desired = {"name": name, "domains": domains, "mode": mode,
"configuration": configuration, "rules": rule_definitions}
publication = osano.CookieConsentPublication(
"publication",
config_id=config.config_id,
change_token=hashlib.sha256(json.dumps(desired, sort_keys=True).encode()).hexdigest(),
opts=pulumi.ResourceOptions(
depends_on=[config, *rules],
custom_timeouts=pulumi.CustomTimeouts(create="20m", update="20m"),
),
)
# Hand the tag to whatever renders or configures the site's <head>; it must come first.
pulumi.export("scriptTag", publication.script_tag)
pulumi.export("headHtml", pulumi.Output.format("<head>\n {0}\n</head>", publication.script_tag))
pulumi preview never publishes. pulumi up creates the configuration and rule, publishes, waits for Osano to finish, and returns <script src="https://cmp.osano.com/{customerId}/{configId}/osano.js"></script>. Running it again without changes publishes nothing.
The publication exports script_src (https://cmp.osano.com/{customerId}/{configId}/osano.js) and script_tag (exactly <script src="{scriptSrc}"></script>). These installation values are deliberately non-secret. Put the tag first in the site <head> without async or defer, so the CMP loads before scripts it may control. The URL never changes between revisions, so a website only needs it once. Publication completion and CDN propagation are separate: Osano's CDN can take up to 15 minutes to serve a new revision, and browsers cache osano.js for up to 24 hours.
Read a configuration from another stack
To use the script in another stack, such as one per website, read it with get_cookie_consent_config_output instead of managing the configuration there:
consent = osano.get_cookie_consent_config_output(config_id="<config-id>")
pulumi.export("headScript", consent.script_tag) # the same value the publication exports
pulumi.export("published", consent.publish_status) # the URL returns 403 until the first publish
Before switching a configuration to production mode, which blocks everything unclassified, get_cookie_consent_discoveries lists what osano.js has discovered that no rule covers yet. The end-to-end workflow guide covers the whole pipeline, including Content Security Policy settings and per-environment configurations.
Unified Consent
The Consent resource submits a consent decision, and the functions read consent state back. This program assumes a project created with pulumi new python with pulumi-osano in requirements.txt:
pulumi config set osano:unifiedConsentApiKey --secret
pulumi config set subjectRef <subject-id> --secret
pulumi config set configId <config-id>
pulumi config set privacyProtocolId <protocol-id>
pulumi up
__main__.py:
import pulumi
import pulumi_osano as osano
cfg = pulumi.Config()
subject_ref = cfg.require_secret("subjectRef")
config_id = cfg.require("configId")
privacy_protocol_id = cfg.require("privacyProtocolId")
subject_type = cfg.get("subjectType") or "verified"
subject = (
osano.ConsentSubjectArgs(anonymous_id=subject_ref)
if subject_type == "anonymous"
else osano.ConsentSubjectArgs(verified_id=subject_ref)
)
consent = osano.Consent(
"example",
subject=subject,
actions=[
osano.ConsentActionArgs(target=privacy_protocol_id, vendor=config_id, action="ACCEPT"),
],
attributes={"pulumiStack": pulumi.get_stack()},
origin="api",
tags=["demo"],
)
pulumi.export("consentId", consent.consent_id)
Destroying the stack removes the logical Pulumi resource but does not delete historical events from Osano (they are immutable).
get_subject and get_unified_consent look anonymous and verified IDs up with the default reference_type (subject); session resolves a session ID. To submit a Global Privacy Control consent, set origin="gpc" and omit actions: Osano derives the actions and the resource exports them as gpc_actions. When a pipeline submits consents on a subject's behalf, set country_code_override (and region_code_override) so Osano does not geolocate the CI runner.
Authentication
Two API keys exist:
| Key | Header | Usage |
|---|---|---|
| Unified Consent API key | x-uc-api-key |
Required for consent submissions and read operations |
| Osano Customer REST API key | x-osano-api-key |
Required for Cookie Consent resources and functions; send_subject_code and verify_subject_code send every configured key, so either this key or the Unified Consent API key is enough |
Configure them with Pulumi config:
pulumi config set osano:unifiedConsentApiKey --secret
pulumi config set osano:osanoApiKey --secret
Or set the OSANO_UC_API_KEY and OSANO_API_KEY environment variables, for example in CI.
Configuration
Provider-level settings (all optional):
| Key | Description |
|---|---|
osano:unifiedConsentApiKey |
Unified Consent API key (secret); OSANO_UC_API_KEY takes precedence when set |
osano:osanoApiKey |
Customer REST API key for Cookie Consent and subject verification (secret); OSANO_API_KEY takes precedence when set |
osano:apiBaseUrl |
Override the Unified Consent API base URL, including any path prefix; defaults to https://uc.api.osano.com; OSANO_API_BASE_URL takes precedence when set |
osano:customerBaseUrl |
Override the Customer REST API base URL; defaults to https://api.osano.com |
osano:requestTimeoutSeconds |
HTTP timeout for Customer REST and Unified Consent calls, default 60 seconds; OSANO_API_TIMEOUT_SECONDS takes precedence when valid |
The deprecated osano:ucApiKey and osano:ucBaseUrl keys are still read as fallbacks for unifiedConsentApiKey and apiBaseUrl.
Learn more
- Examples, including a Python Unified Consent quickstart
- End-to-end workflow guide: install, deploy, day-2 changes, import, and teardown
- Troubleshooting and upgrade notes
- Changelog
- Osano's Consent JavaScript API and Customer REST API
publishConfigoperation
Release files for pulumi-osano 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pulumi_osano-0.2.1.tar.gz | 40.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pulumi_osano-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 99.2 kB
Release files / pulumi_osano-0.2.1.tar.gz
| Download URL | pulumi_osano-0.2.1.tar.gz |
|---|---|
| Size | 40.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
451eb178e58cf9d9acbad43a291836241384c2ad27e909852ab01e986eef14d9
|
|
BLAKE2b-256 checksum How to use checksums |
d8c33997b76546e3152fb90ca2e9c685d090f8b7f918832f5fced9b2c1e66a53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / pulumi_osano-0.2.1-py3-none-any.whl
| Download URL | pulumi_osano-0.2.1-py3-none-any.whl |
|---|---|
| Size | 59.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ae21045c9bd9c0c63232dfe83ec48c52a3e639dd348de06c92ee9a83bde70d7
|
|
BLAKE2b-256 checksum How to use checksums |
dda077fa382ca4600f025636fdc4f463a0d164f15e115926a9016c857d0fae9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log