# Getting started: LiveObjects in Python
> **Note**
>
> **Building with LiveObjects?** Help shape its future by [sharing your use case](https://44qpp.share.hsforms.com/2fZobHQA1ToyRfB9xqZYQmQ).
This guide shows how to integrate Ably LiveObjects into your Python application.
You will learn how to:
* Create an Ably account and get an API key for authentication.
* Install the Ably Pub/Sub SDK.
* Create a channel with LiveObjects functionality enabled.
* Use the [PathObject API](https://ably.com/docs/liveobjects/concepts/path-object.md) to access objects on a channel.
* Create, update and subscribe to changes on LiveObjects data structures: [LiveMap](https://ably.com/docs/liveobjects/map.md) and [LiveCounter](https://ably.com/docs/liveobjects/counter.md).
## Authentication
An [API key](https://ably.com/docs/auth.md#api-keys) is required to authenticate with Ably. API keys are used either to authenticate directly with Ably using [basic authentication](https://ably.com/docs/auth/basic.md), or to generate tokens for untrusted clients using [token authentication](https://ably.com/docs/auth/token.md).
> **Important**
>
> The examples use [basic authentication](https://ably.com/docs/auth/basic.md) to demonstrate features for convenience. In your own applications, basic authentication should never be used on the client-side as it exposes your Ably API key. Instead use [token authentication](https://ably.com/docs/auth/token.md).
[Sign up](https://ably.com/sign-up) for a free account and create your own API key in the [dashboard](https://ably.com/dashboard) or use the [Control API](https://ably.com/docs/platform/account/control-api.md) to create an API key programmatically.
API keys and tokens have a set of [capabilities](https://ably.com/docs/auth/capabilities.md) assigned to them that specify which operations can be performed on which resources. The following capabilities are available for LiveObjects:
* `object-subscribe` - grants clients read access to LiveObjects, allowing them to get the channel object and subscribe to updates.
* `object-publish` - grants clients write access to LiveObjects, allowing them to perform mutation operations on objects.
To use LiveObjects, an API key must have at least the `object-subscribe` capability. With only this capability, clients will have read-only access, preventing them from calling mutation methods on LiveObjects.
For the purposes of this guide, make sure your API key includes both `object-subscribe` and `object-publish` [capabilities](https://ably.com/docs/auth/capabilities.md) to allow full read and write access.
## Install Ably Pub/Sub SDK
LiveObjects is built into the realtime client of the Ably Pub/Sub Python SDK, `ably-pubsub-server`, from version 4.0. No plugin is needed. The SDK requires Python 3.8 or later:
### Shell
```
pip install ably-pubsub-server
```
## Instantiate a client
The client is asynchronous and built on `asyncio`, so it must be created inside a running event loop. Instantiate an Ably Realtime client from the Pub/Sub SDK inside an `async def main()` coroutine, and start it with `asyncio.run()`:
### Python
```
import asyncio
from ably.pubsub.server import ChannelMode, ChannelOptions, create_realtime_client
from ably.pubsub.server.liveobjects import LiveCounter, LiveMap
async def main():
pubsub_realtime_client = create_realtime_client(key='your-api-key')
# Add the code from the following steps here
asyncio.run(main())
```
Add the code from each of the following steps inside `main()`.
Other client options can be passed as keyword arguments to `create_realtime_client()` to further customize the connection, however at a minimum you must set an API key. LiveObjects writes require the `echo_messages` client option, which is enabled by default.
## Create a channel
LiveObjects is managed and persisted on [channels](https://ably.com/docs/channels.md). To use LiveObjects, you must first create a channel with the correct [channel mode flags](https://ably.com/docs/channels/options.md#modes):
* `OBJECT_SUBSCRIBE` - required to access objects on a channel.
* `OBJECT_PUBLISH` - required to create and modify objects on a channel.
> **Note**
>
> When you provide an explicit `modes` field for a channel, you override the set of [default modes](https://ably.com/docs/channels/options.md#modes) used for that channel. So, if you're using the channel for anything in addition to LiveObjects, you need to ensure that you also include the other modes required by the features you are using.
### Python
```
channel = pubsub_realtime_client.channels.get(
'test-channel',
ChannelOptions(modes=[ChannelMode.OBJECT_PUBLISH, ChannelMode.OBJECT_SUBSCRIBE]),
)
```
## Get the channel object
The `channel.object` attribute gives access to the LiveObjects API for a channel.
Use `channel.object.get()` to obtain the channel object. The channel object is a [`LiveMap`](https://ably.com/docs/liveobjects/map.md) that always exists on a channel and acts as the top-level entry point for accessing and persisting objects. It is returned as a [`LiveMapPathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md#get), which provides a path-based API for accessing and manipulating the object hierarchy.
`channel.object.get()` is a coroutine that returns once the LiveObjects state is synchronized with the Ably system. Mutations are coroutines too, so you `await` them, while reads are synchronous and local:
### Python
```
root_object = await channel.object.get()
```
> **Note**
>
> Calling `channel.object.get()` implicitly attaches to the channel if it's not already attached. You don't need to manually call `channel.attach()` before getting the object.
## Create and assign objects
You can create and assign objects using the `LiveMap.create()` and `LiveCounter.create()` static methods. These methods return a description of the object to create; the actual object is created when you assign it to a key with `set()`:
### Python
```
# Create a LiveCounter with initial value 0 and assign it to the 'visits' key on the channel object
await root_object.set('visits', LiveCounter.create(0))
# Create a LiveMap with initial entries and assign it to the 'reactions' key on the channel object
await root_object.set('reactions', LiveMap.create({
'likes': 0,
'hearts': 0,
}))
# Infer types for the assigned objects
visits_counter = root_object.get('visits').as_live_counter()
reactions_map = root_object.get('reactions').as_live_map()
```
`root_object.get(key)` returns a general [`PathObject`](https://ably.com/docs/liveobjects/concepts/path-object.md) that doesn't yet know the type of the value it points to. Call `as_live_counter()`, `as_live_map()` or `as_primitive()` to work with the value as a specific type. These views are always safe to call: they never raise an exception, even if the value at the path has a different type. Learn more about [Type inference](https://ably.com/docs/liveobjects/typing.md#type-inference).
> **Note**
>
> You can create deeply nested structures in a single operation by nesting `LiveMap.create()` and `LiveCounter.create()` calls.
## Subscribe to updates
Subscribe to realtime updates using the `subscribe()` method on a `PathObject`. You will be notified when the object at that path is updated by other clients or by you:
### Python
```
# Subscribe to counter updates
def on_visits_update(event):
print('Visits counter updated:', event.object.as_live_counter().value())
visits_subscription = visits_counter.subscribe(on_visits_update)
# Subscribe to map updates
def on_reactions_update(event):
print('Reactions updated:', event.object.compact_json())
reactions_subscription = reactions_map.subscribe(on_reactions_update)
```
The listener is a regular function, called synchronously with an event that exposes:
- `object`: A `PathObject` pointing to the path where the change occurred
- `message`: The `ObjectMessage` that carried the operation that led to the change, or `None`
The `subscribe()` method returns a `Subscription` object. When you no longer want to receive updates, call `unsubscribe()` on it:
### Python
```
# Later, stop receiving updates
visits_subscription.unsubscribe()
```
## Update objects
Update objects using mutation methods on `PathObject`. All subscribers (including you) will be notified of the changes:
### Python
```
# Update counter
await visits_counter.increment(5)
# console: Visits counter updated: 5.0
await visits_counter.decrement(2)
# console: Visits counter updated: 3.0
# Update map
await reactions_map.set('likes', 10)
# console: Reactions updated: {'likes': 10.0, 'hearts': 0.0}
await reactions_map.set('hearts', 5)
# console: Reactions updated: {'likes': 10.0, 'hearts': 5.0}
await reactions_map.remove('likes')
# console: Reactions updated: {'hearts': 5.0}
```
> **Note**
>
> Mutation methods send operations to the Ably system and apply changes locally as soon as the operations are acknowledged. Once the awaited call returns, the operation has been applied locally and you can read the updated state immediately. You will also be notified via subscription when the object is updated.
## Next steps
This quickstart introduced the basic concepts of LiveObjects and demonstrated how the path-based API works. The next steps are to:
* Learn about the [PathObject](https://ably.com/docs/liveobjects/concepts/path-object.md) and [Instance](https://ably.com/docs/liveobjects/concepts/instance.md) APIs.
* Read more about [LiveCounter](https://ably.com/docs/liveobjects/counter.md) and [LiveMap](https://ably.com/docs/liveobjects/map.md).
* Learn about [Objects Lifecycle Events](https://ably.com/docs/liveobjects/lifecycle.md).
* Learn about [Type inference](https://ably.com/docs/liveobjects/typing.md) for your LiveObjects.
## Related Topics
- [JavaScript](https://ably.com/docs/liveobjects/quickstart/javascript.md): A getting started guide to learn the basics of integrating the Ably LiveObjects product into your JavaScript application.
- [Swift](https://ably.com/docs/liveobjects/quickstart/swift.md): A quickstart guide to learn the basics of integrating the Ably LiveObjects product into your Swift application.
- [Java](https://ably.com/docs/liveobjects/quickstart/java.md): A quickstart guide to learn the basics of integrating the Ably LiveObjects product into your Java application.
## Documentation Index
To discover additional Ably documentation:
1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages.
2. Identify relevant URLs from that index.
3. Fetch target pages as needed.
Avoid using assumed or outdated documentation paths.