# Databricks Isv Telemetry Attribution

> PWAF User-Agent telemetry: format, per-driver configuration (Python SDK, Java SDK/JDBC, Go SDK/SQL, Node.js, REST, Databricks Connect). Use when setting up User-Agent attribution in any connector.

- Skill: `databricks-solutions/databricks-isv-telemetry-attribution` (Agent Skill)
- Install (CLI): `npx skillmds@latest add databricks-solutions/databricks-isv-telemetry-attribution`
- Raw SKILL.md: https://api.skillmd.com/api/skills/databricks-solutions/databricks-isv-telemetry-attribution/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: databricks-solutions (https://skillmd.com/u/databricks-solutions)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/databricks-solutions/databricks-isv-telemetry-attribution

---


<!-- skill-version: 1.0.0 -->

# Telemetry & Attribution (PWAF)

User-Agent configuration for PWAF-compliant partner integrations across all Databricks drivers and SDKs. Reference: [PWAF Telemetry & Attribution](https://databrickslabs.github.io/partner-architecture/isv-partners/telemetry-attribution/).

## Why Telemetry is Required

PWAF requires User-Agent tagging in all partner integrations for:

| Purpose | Description |
|---------|-------------|
| **Usage Attribution** | Track partner product usage for reporting |
| **Joint Customer Visibility** | Identify how many joint customers use the integration |
| **GTM Initiatives** | Measure integration adoption and effectiveness |

## User-Agent Format

**Required format**:

```
<isv-name>_<product-name>/<product-version>
```

**Rules**:
- Use underscore (`_`) as separator between ISV name and product name
- Use forward slash (`/`) before version
- Keep ISV name consistent across all products
- Version is optional but recommended

**Examples**:
```
AcmePartner_DataConnector/2.1.0
BigCorp_ETLTool/3.5
MyCompany_AnalyticsPlatform/1.0.0-beta
```

---

## SDK-level User-Agent Registration (withPartner / withProduct)

Per [PWAF SDKs telemetry](https://databrickslabs.github.io/partner-architecture/isv-partners/telemetry-attribution/sdks), Databricks **SDKs** use dedicated static/global registration functions. These register product and partner identifiers that are applied to **all** subsequent SDK HTTP requests. Call once before creating any client.

### Java SDK

```java
import com.databricks.sdk.core.UserAgent;

UserAgent.withProduct("<product-name>", "<product-version>");
UserAgent.withPartner("<isv-name>");

// Then create WorkspaceClient as normal
WorkspaceClient client = new WorkspaceClient(config);
```

### Python SDK

```python
from databricks.sdk import WorkspaceClient, useragent

useragent.with_partner("<isv-name>")
useragent.with_product("<product-name>", "<product-version>")

# Then create WorkspaceClient as normal
client = WorkspaceClient(host="https://<host>", token="<token>")
```

### Go SDK

```go
import (
    "github.com/databricks/databricks-sdk-go"
    "github.com/databricks/databricks-sdk-go/useragent"
)

useragent.WithPartner("<isv-name>")
useragent.WithProduct("<product-name>", "<product-version>")

// Then create WorkspaceClient as normal
client, err := databricks.NewWorkspaceClient(&databricks.Config{...})
```

### Summary table

| SDK | Partner function | Product function | Scope |
|-----|-----------------|------------------|-------|
| **Java** | `UserAgent.withPartner(isv)` | `UserAgent.withProduct(name, ver)` | Static/global |
| **Python** | `useragent.with_partner(isv)` | `useragent.with_product(name, ver)` | Module/global |
| **Go** | `useragent.WithPartner(isv)` | `useragent.WithProduct(name, ver)` | Package/global |

**Note:** These SDK functions are distinct from the driver-level `UserAgentEntry` property used by JDBC, ODBC, Node.js SQL driver, and Databricks SQL Driver for Go. Both approaches use the same `<isv>_<product>/<version>` format; the SDK functions decompose it into separate partner and product registrations.

---

## JDBC Driver (OSS)

Per [PWAF SQL Drivers telemetry](https://databrickslabs.github.io/partner-architecture/isv-partners/telemetry-attribution/sql-drivers), set `UserAgentEntry` on every JDBC connection.

### Using JDBC URL

```java
String jdbcUrl = 
    "jdbc:databricks://<host>:443;" +
    "httpPath=<http-path>;" +
    "AuthMech=11;" +
    "Auth_Flow=1;" +
    "OAuth2ClientId=<client-id>;" +
    "OAuth2Secret=<client-secret>;" +
    "SSL=1;" +
    "UserAgentEntry=YourCompany_YourProduct/1.0.0";

Connection conn = DriverManager.getConnection(jdbcUrl);
```

### Using Properties

```java
Properties props = new Properties();
props.put("httpPath", "<http-path>");
props.put("AuthMech", "11");
props.put("Auth_Flow", "1");
props.put("OAuth2ClientId", "<client-id>");
props.put("OAuth2Secret", "<client-secret>");
props.put("SSL", "1");
props.put("UserAgentEntry", "YourCompany_YourProduct/1.0.0");

Connection conn = DriverManager.getConnection("jdbc:databricks://<host>:443", props);
```

### Using DataSource

```java
import com.databricks.client.jdbc.DataSource;

DataSource ds = new DataSource();
Properties props = new Properties();
props.setProperty("UserAgentEntry", "YourCompany_YourProduct/1.0.0");
props.setProperty("AuthMech", "11");
props.setProperty("Auth_Flow", "1");
props.setProperty("OAuth2ClientId", "<client-id>");
props.setProperty("OAuth2Secret", "<client-secret>");
props.setProperty("SSL", "1");

ds.setServerHostname("<host>");
ds.setPort(443);
ds.setHttpPath("<http-path>");
ds.setProperties(props);

Connection conn = ds.getConnection();
```

---

## ODBC Driver

### DSN Configuration (Linux/Mac)

In `~/.odbc.ini` or `/etc/odbc.ini`:

```ini
[DatabricksConnection]
Driver=/opt/simba/spark/lib/64/libsparkodbc_sb64.so
Host=<server-hostname>
Port=443
HTTPPath=<http-path>
SSL=1
ThriftTransport=2
AuthMech=11
Auth_Flow=1
OAuth2ClientId=<client-id>
OAuth2Secret=<client-secret>
UserAgentEntry=YourCompany_YourProduct/1.0.0
```

### DSN-less Connection String

```
Driver=/opt/simba/spark/lib/64/libsparkodbc_sb64.so;
Host=<server-hostname>;
Port=443;
HTTPPath=<http-path>;
SSL=1;
ThriftTransport=2;
AuthMech=11;
Auth_Flow=1;
OAuth2ClientId=<client-id>;
OAuth2Secret=<client-secret>;
UserAgentEntry=YourCompany_YourProduct/1.0.0;
```

---

## Node.js Driver

```javascript
const { DBSQLClient } = require('@databricks/sql');

const client = new DBSQLClient();

await client.connect({
    host: process.env.DATABRICKS_HOST,
    path: process.env.DATABRICKS_HTTP_PATH,
    token: process.env.DATABRICKS_TOKEN,  // or OAuth config
    userAgentEntry: 'YourCompany_YourProduct/1.0.0'
});

const session = await client.openSession();
const result = await session.executeStatement('SELECT 1');
```

---

## Go Driver

```go
package main

import (
    "database/sql"
    "os"
    
    dbsql "github.com/databricks/databricks-sql-go"
)

func main() {
    connector, err := dbsql.NewConnector(
        dbsql.WithServerHostname(os.Getenv("DATABRICKS_HOST")),
        dbsql.WithPort(443),
        dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
        dbsql.WithAccessToken(os.Getenv("DATABRICKS_TOKEN")),
        dbsql.WithUserAgentEntry("YourCompany_YourProduct/1.0.0"),
    )
    if err != nil {
        panic(err)
    }
    
    db := sql.OpenDB(connector)
    defer db.Close()
    
    // Execute queries...
}
```

---

## Python SQL Connector

```python
from databricks import sql

connection = sql.connect(
    server_hostname="<host>",
    http_path="<http-path>",
    access_token="<token>",  # or OAuth config
    _user_agent_entry="YourCompany_YourProduct/1.0.0"
)

cursor = connection.cursor()
cursor.execute("SELECT 1")
print(cursor.fetchall())
cursor.close()
connection.close()
```

---

## Python SQLAlchemy

Use `user_agent_entry` in `connect_args` (not `_user_agent_entry`; the latter is deprecated):

```python
from sqlalchemy import create_engine, text

url = "databricks://token:<token>@<host>?http_path=<path>&catalog=main&schema=default"
engine = create_engine(url, connect_args={"user_agent_entry": "YourCompany_YourProduct/1.0.0"})

with engine.connect() as conn:
    conn.execute(text("SELECT 1"))
```

---

## Python SDK

Use the `useragent` module functions (recommended) for partner and product registration:

```python
from databricks.sdk import WorkspaceClient, useragent

# Register partner and product (global, call once)
useragent.with_partner("YourCompany")
useragent.with_product("YourCompany_YourProduct", "1.0.0")

client = WorkspaceClient(
    host="https://<host>",
    token="<token>",
)
```

**Note:** The older `product=` / `product_version=` on `WorkspaceClient` or `Config` also works but `useragent.with_partner()` / `useragent.with_product()` is the recommended approach for partner integrations.

---

## REST API (Direct HTTP)

When calling Databricks REST APIs directly, include the User-Agent header:

```bash
curl -X GET "https://<host>/api/2.0/clusters/list" \
  -H "Authorization: Bearer <token>" \
  -H "User-Agent: YourCompany_YourProduct/1.0.0"
```

### Java (HttpClient)

```java
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://<host>/api/2.0/clusters/list"))
    .header("Authorization", "Bearer " + token)
    .header("User-Agent", "YourCompany_YourProduct/1.0.0")
    .GET()
    .build();

HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());
```

---

## Databricks Connect

Use `.userAgent()` on the `DatabricksSession.builder` to set the partner User-Agent identifier. This is the [PWAF-recommended approach](https://databrickslabs.github.io/partner-architecture/isv-partners/telemetry-attribution/databricks-connect).

### Python

```python
from databricks.connect import DatabricksSession
from databricks.sdk.core import Config

config = Config()  # Auth from environment

spark = (
    DatabricksSession.builder
        .sdkConfig(config)
        .userAgent("YourCompany_YourProduct/1.0.0")
        .getOrCreate()
)
```

### Scala

```scala
import com.databricks.connect.DatabricksSession

val spark = DatabricksSession.builder
    .userAgent("YourCompany_YourProduct/1.0.0")
    .getOrCreate()
```

**Note:** The older `product=` / `product_version=` on Config also works internally, but `.userAgent()` on the session builder is the official PWAF pattern.

---

## Validating Your Implementation

### Method 1: Query History UI

1. Go to Databricks workspace → SQL → Query History
2. Look for the **Source** column
3. Your User-Agent should appear there

### Method 2: System Tables Query

```sql
SELECT 
    event_time,
    user_agent,
    action_name,
    request_params
FROM system.access.audit
WHERE event_time > current_timestamp() - INTERVAL 2 DAYS
  AND lower(user_agent) LIKE '%yourcompany%'
ORDER BY event_time DESC
LIMIT 100;
```

**Note**: Request access to system tables if needed.

---

## Common Mistakes

| Mistake | Consequence | Fix |
|---------|-------------|-----|
| Using space instead of underscore | Inconsistent attribution | Use `Company_Product` not `Company Product` |
| Customer configures User-Agent | Unreliable tracking | Set it programmatically in your code |
| Missing User-Agent entirely | No partner attribution | Always include `UserAgentEntry` |
| Hardcoding wrong format | Parsing issues | Follow `<isv>_<product>/<version>` format |
| Different UA across products | Split attribution | Use consistent ISV name |

