# splunk-sdk-python: talking to the Splunk REST API from Python

> The Splunk Enterprise SDK for Python is the intended way to reach the Splunk platform's REST API, and in version 3 it dropped its runtime dependencies entirely and moved the AI integrations into optional extras. What remains is a client library, a search commands framework and a set of packaging rules for Apps.

**splunk/splunk-sdk-python** — Splunk Software Development Kit for Python

- Repository: https://github.com/splunk/splunk-sdk-python
- Website: http://dev.splunk.com
- Stars: 747 · Forks: 387
- Language: Python
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/splunk-splunk-sdk-python

## The vendor's own client for its own REST API

The Splunk Enterprise SDK for Python is intended to be the primary way for developers to communicate with the Splunk platform's REST API. That is the positioning, and it is worth taking at face value: this is the first-party client, maintained in the vendor's own repository, and it is Apache-2.0 licensed.

The repository structure reflects the two audiences it serves. The splunklib/ directory is the library itself, the tests/ directory holds a unit test suite and a system test suite, and the examples/ directory contains three complete Apps: ai_custom_alert_app, ai_custom_search_app and ai_modinput_app. There is also a docs/ directory, a scripts/ directory, a utils/ directory and a Dockerfile with a compose.yml beside it, which is how the project runs a real Splunk instance for its system tests.

The distinction the README draws is one that will trip you up if you skip it. The repository contains splunklib, whereas splunk is an internal library bundled with the Splunk platform. So when you see import splunk in a Splunk environment and import splunklib in your own code, those are two different packages, and the SDK is the one you install from PyPI.

The version history shows a major release recently. Version 2.1.1 was released on 2025-08-26, 3.0.0 on 2026-05-12 and 3.0.1 on 2026-09-09, with the last push on 2026-10-08 and the default branch named develop. The project metadata lists the development status as 6, Mature.

## A dependency-free core, with the heavy parts behind extras

The most striking thing in the project metadata is the dependency list, which is empty. The dependencies array has nothing in it at all, and the only unconditional requirement is Python 3.13 or newer.

Everything else is optional, and the extras are named for what they enable. The compat extra pulls in six at 1.17.0 or newer, which the comment in the file explains is there to treat the same way as an npm dependencies entry. The ai extra is the substantial one, with httpx pinned at 0.28.1, langchain at 1.3.15 or newer, the Model Context Protocol package at 1.28.1 and below 2.0.0, and pydantic at 2.13.4 or newer.

On top of that sit four provider extras that each compose the ai extra with a specific backend. The anthropic extra installs the ai extra plus langchain-anthropic, the openai extra installs the ai extra plus langchain-openai, and the google extra installs the ai extra plus langchain-google-genai pinned at 4.3.4 and google-auth at 2.56.3 or newer.

This structure is a deliberate design choice with a real consequence. A user who only needs the REST client installs nothing but the SDK, and a user building an agentic App installs the model context protocol and one provider integration and nothing else. The cost of the split is that the versions are exact in places, so the extras have to be updated together when a dependency moves.

The AI capability itself is exposed through the splunklib.ai package, and the README points at its own README for details on enhancing Apps with agentic behaviour and custom tools.

## Connecting with a password, a bearer token or a session key

The connection API is the part you will use first, and it has three forms, all going through the same connect function in splunklib.client.

With a username and password:

```python
import splunklib.client as client

service = client.connect(host=<HOST_URL>, username=<USERNAME>, password=<PASSWORD>, autologin=True)
```

With a bearer token:

```python
import splunklib.client as client

service = client.connect(host=<HOST_URL>, splunkToken=<BEARER_TOKEN>, autologin=True)
```

And with a session key:

```python
import splunklib.client as client

service = client.connect(host=<HOST_URL>, token=<SESSION_KEY>, autologin=True)
```

The parameter names differ between the three, and that is the detail to get right. The bearer token goes in as splunkToken, while the session key goes in as token. Mixing those up is the kind of error that produces an authentication error rather than a clear message about the wrong keyword.

All three set autologin=True, which is the behaviour you want in a script that makes a series of calls: the session is established once and reused rather than re-authenticated on every request.

The README's own recommendation for learning the library is to read the apps in the test suite and the separate splunk-app-examples repository, which show programmatic interaction in a variety of scenarios, from basic metadata retrieval and one-shot searching to managing saved searches and building complete applications with modular inputs and custom search commands.

## Custom search commands, and the two rules that bite

The search commands framework is the most substantial part of the SDK, and it comes with conventions you have to follow or your command will misbehave in ways that are hard to trace.

The base classes are StreamingCommand, GeneratingCommand and similar. Inside a command, the service metadata object is available, created from the splunkd URI and the session key passed to the command invocation:

```python
from splunklib.searchcommands import StreamingCommand


class MyCommand(StreamingCommand):
    def get_metadata(self):
        # Access instance metadata
        service = self.service
        # Access Splunk service info
        info = service.info
        # [...]
```

The first rule is about adding fields to records. When you add new fields to records based on certain conditions, structural changes like that may not be preserved, and the fix is to use the add_field method from SearchCommand rather than assigning to the record directly. The documentation shows the difference as a diff, where a plain assignment is replaced by the method call:

```diff
class CustomStreamingCommand(StreamingCommand):
    def stream(self, records):
        for index, record in enumerate(records):
            if index % 1 == 0:
-                record["odd_record"] = "true"
+                self.add_field(record, "odd_record", "true")
            yield record
```

The second rule is about generating events. Use the gen_record method from SearchCommand to add a new record, and pass the event data as comma-separated key=value pairs:

```diff
@Configuration()
class GeneratorTest(GeneratingCommand):
    def generate(self):
-        yield {'_time': time.time(), 'one': 1}
-        yield {'_time': time.time(), 'two': 2}
+        yield self.gen_record(_time=time.time(), one=1)
+        yield self.gen_record(_time=time.time(), two=2)
```

Both rules point the same way. The framework does bookkeeping on records that a direct assignment bypasses, which is why the structural change may not survive. Modular inputs follow the same pattern, where the service metadata object is available as soon as the stream_events method runs.

## Packaging an App, and the platform mismatch that catches people out

Packaging a Splunk App has a rule that is easy to miss and expensive to get wrong, because of the way Splunk Apps are built. You need to install your external dependencies into bin/lib/ for the App to work, and then in your App script files you add that directory to the path:

```python
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "lib"))
```

The packaging workflow itself is a pip install with a target directory, followed by a gtar that repackages the tree:

```sh
python3 -m pip install . \
  --target bin/lib/ \
  # Needs to match the platform Splunk is built and
  # ran on, NOT the one you're writing your App on
  --platform manylinux2014_aarch64 \
  --only-binary=:all:

gtar --transform='s,^,<your_app>/,' \
  --exclude="__pycache__" \
  -czf dist/<your_app>.tgz \
  bin default
```

The comment inside the command is the important part. The platform has to match the platform Splunk is built and running on, not the one you are writing the App on. The example targets manylinux2014_aarch64 with only-binary, which is the combination that produces a self-contained directory of compiled dependencies that Splunk can import at runtime regardless of what is installed on the host.

The gtar step then rewrites the paths so the app directory has the name Splunk expects, excludes the Python bytecode cache, and writes a tarball into dist/ that is ready to upload. The README is upfront that this is an example workflow you will need to modify heavily, which is fair, because the platform string and the app name are the two things that change for every project.

## Where the Splunk SDK is the wrong choice

The first wrong case is a handful of searches. If you need to run a search, read some results and move on, the REST API is directly callable with requests or httpx and you would be installing a large package to avoid writing three lines. The SDK earns its weight when you are building an App or a tool with real structure, not when you are scripting a query.

The second is an environment where you cannot install Python 3.13. The floor moved with version 3, and the extras pin httpx, langchain and the model context protocol to specific versions. If your build image is on an older Python, the SDK is not available to you in a form that matches the documentation, and the older 2.x line is a different API surface.

The third is a deployment where the platform mismatch bites. Because the dependencies are installed for the target platform rather than your own, you need to produce a manylinux build for whatever architecture Splunk runs on. That is a real constraint on a Mac or Windows development machine, and the workflow shows it happening but does not remove the requirement.

The fourth is using it outside Splunk. The SDK talks to the Splunk REST API and implements Splunk App conventions, so the search command classes and the bin/lib packaging rule are Splunk specific and have no meaning anywhere else. If what you want is a log analytics client that works against several backends, this is the wrong shape of dependency, because you are adopting Splunk's App model along with its API client.

The alternative worth weighing is calling the REST API directly with httpx, which is what the empty dependency list makes possible, at the cost of handling sessions, retries and the App packaging rules yourself.

## Conclusion

Adopt splunk-sdk-python if you are writing a Splunk App or an internal tool that talks to Splunk Enterprise or Cloud, since it is the vendor's own client and the search commands framework saves you from hand-rolling the record plumbing. Keep away if you only need to run a handful of searches, because the REST API is directly callable and this is a large package for that. Before you start, check the Python floor, since version 3.0.1 requires Python 3.13 or newer, and note the packaging rule that your App's dependencies must be installed into bin/lib/ for the target platform Splunk runs on, not the platform you develop on.

## FAQ

### How do I install the Splunk SDK for Python?

With uv, run uv init, uv add splunk-sdk and uv sync. With pip, create a virtual environment with python3 -m venv .venv, activate it with source .venv/bin/activate and run python3 -m pip install splunk-sdk. The SDK requires Python 3.13 or newer and Splunk Enterprise or Cloud.

### What is the difference between import splunklib and import splunk?

The repository contains splunklib, which is what you install from PyPI, whereas splunk is an internal library bundled with the Splunk platform. The SDK is the splunklib package.

### How do I connect to Splunk from Python with the SDK?

Use client.connect from splunklib.client with a host URL and either a username and password, a bearer token passed as splunkToken, or a session key passed as token. Setting autologin=True establishes the session once and reuses it across calls.

### Why must a Splunk App install its dependencies into bin/lib?

Because of the way Splunk Apps are built, the external dependencies have to live in bin/lib for the App to work, and the App script files add that directory to sys.path. The packaging install also targets the platform Splunk runs on rather than the one you develop on, and the comment in the example command spells that out.

## Sources

- [License: Apache-2.0](https://github.com/splunk/splunk-sdk-python/blob/develop/LICENSE)
- [Project website](http://dev.splunk.com)
- [README](https://github.com/splunk/splunk-sdk-python/blob/develop/README.md)
- [Releases](https://github.com/splunk/splunk-sdk-python/releases)
- [splunk/splunk-sdk-python on GitHub](https://github.com/splunk/splunk-sdk-python)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/splunk-splunk-sdk-python
