Skip to main content

8.3 - Optional - Using the Raw API

The python-sc2 library is an abstraction layer. It acts as a sophisticated translator, converting the complex, raw data stream from the StarCraft II engine into clean, easy-to-use Python objects like Unit and Units. For 99% of developers, this high-level interface is the best and most productive way to build a bot.

However, for advanced users who require absolute control or need to access data not exposed by the high-level helpers, the library provides a direct "escape hatch" to the raw API data.

Warning: This is an advanced topic. Using the raw API requires a deep understanding of the underlying game protocol and significantly increases code complexity.

The Data Flow: High-Level vs. Raw

This diagram illustrates the two paths data can take to your bot's logic.

+--------------------+
| SC2 Game Engine |
+--------------------+
|
| (Sends complex Protobuf data)
v
+--------------------+
| python-sc2 Library|
+--------------------+
|
| (Translates and simplifies)
v
.-----------------------------------------. <-- The Standard Path (Recommended)
| High-Level Helpers (self.units, etc.) | (Clean, easy-to-use Python objects)
`-----------------------------------------`
|
| (Provides a direct passthrough)
v
.-----------------------------------------. <-- The Raw Path (Advanced)
| Raw API (self.observation_raw) | (Complex, nested Protobuf objects)
`-----------------------------------------`

Why and When to Use the Raw API

ScenarioDescription
1. Accessing Unexposed DataThe most legitimate reason. There may be rare or newly added data fields in the game's protocol that python-sc2 does not yet parse into a high-level helper. The raw API is your only way to access these.
2. Extreme Performance OptimizationFor top-tier competitive bots, the process of creating Python Unit objects on every step can introduce a tiny amount of overhead. An expert might bypass this by creating their own, more efficient data structures directly from the raw data. This is a significant undertaking.
3. Library DebuggingIf you suspect a bug in how python-sc2 is interpreting the game state, you can compare the data from the high-level helpers against the "ground truth" provided by the raw API to diagnose the issue.

The Trade-Offs: What You Gain and What You Lose

AspectHigh-Level API (self.units)Raw API (self.observation_raw.raw_data.units)
Ease of UseVery High. Clean objects, intuitive property names.Very Low. Deeply nested, verbose Protobuf objects.
Readabilityif marine.is_idle:if not raw_marine.orders:
Helper MethodsAbundant. .distance_to, .target_in_range, etc.None. You must implement all calculations yourself.
PerformanceExcellent for almost all use cases.Potentially faster, but only if you build a highly optimized custom data layer to replace the library's.
ControlHigh.Absolute. Direct access to every field the API provides.

Code Example: A Raw Data Inspector

This example demonstrates how to access the raw Protobuf objects and contrasts them with their high-level equivalents. Note the verbosity and the different property names.

# raw_api_inspector.py

from sc2 import maps
from sc2.bot_ai import BotAI
from sc2.data import Difficulty, Race
from sc2.main import run_game
from sc2.player import Bot, Computer
# Import the raw protocol buffer definitions.
from s2clientprotocol import sc2api_pb2 as sc_pb

class RawAPIInspectorBot(BotAI):
"""A bot that inspects and compares raw vs. high-level API data."""

async def on_step(self, iteration: int):
# We only want to run this once to avoid spamming the console.
if iteration == 5:
marine = None
print("--- High-Level API (Recommended) ---")
# Get the first unit using the clean, high-level interface.
# Safely get the first unit, if one exists.
if self.units:
marine = self.units.first
print(f"Unit: {marine.name}")
print(f"Health: {marine.health}/{marine.health_max}")
print(f"Position: {marine.position.rounded}")
else:
print("No units found with the high-level API.")


print("\n--- Raw API (Advanced) ---")
# Get the raw observation object for the current step.
observation: sc_pb.Observation = self.observation_raw
# Access the list of raw unit Protobufs.
raw_units = observation.raw_data.units

# Find the raw unit with the same tag as our high-level marine.
# This check will only succeed if a unit was found above.
if marine:
raw_marine_proto = next((u for u in raw_units if u.tag == marine.tag), None)
if raw_marine_proto:
# Note the different property names and data types.
print(f"Unit Tag: {raw_marine_proto.tag}")
print(f"Unit Type ID: {raw_marine_proto.unit_type}")
print(f"Health: {raw_marine_proto.health}/{raw_marine_proto.health_max}")
# Position is a nested object.
print(f"Position: (x={raw_marine_proto.pos.x:.2f}, y={raw_marine_proto.pos.y:.2f})")
else:
print(f"Could not find raw unit with tag {marine.tag}")
elif raw_units:
print(f"Total raw units found: {len(raw_units)}")
else:
print("No units found with the raw API.")


if __name__ == "__main__":
run_game(
maps.get("AcropolisLE"),
[
Bot(Race.Terran, RawAPIInspectorBot()),
Computer(Race.Zerg, Difficulty.Easy)
],
realtime=True,
)

Conclusion: The raw API is a powerful tool for experts with specific, demanding requirements. For all other developers, the standard high-level interface provides the ideal balance of power, performance, and readability.