# Billing LiveObjects operations are billed as messages. This page explains how different LiveObjects operations contribute to your Ably usage. ## Message counting Each operation is sent as an [`ObjectMessage`](https://ably.com/docs/liveobjects/concepts/operations.md?source=llms.txt#properties). Ably bills for each outbound message sent from a client, and for each inbound message delivered to each client. When a client performs an operation (such as setting a value on a `LiveMap` or incrementing a `LiveCounter`), this generates an outbound message. When that operation is broadcast to other connected clients, each client receives an inbound message. For example, if 5 clients are connected to a channel and one client increments a counter: - 1 outbound message (from the client performing the increment) - 5 inbound messages (one delivered to each of the 5 connected clients, including the client that sent it) ## LiveMap operations Removing a key and setting a primitive value always sends one message: ### Javascript ``` // One message await myObject.get('settings').set('theme', 'dark'); // One message await myObject.get('settings').remove('theme'); ``` Creating a shallow `LiveMap` sends two messages: one to create the new `LiveMap` object, and one to assign it to the target object: ### Javascript ``` // Two messages: create map + assign to 'settings' await myObject.set('settings', LiveMap.create({ shallow: 'data' })); ``` Nested `LiveMap` or `LiveCounter` objects each generate their own creation messages: ### Javascript ``` // Four messages: // - create visits counter // - create stats map // - create settings map // - assign to 'settings' await myObject.set('settings', LiveMap.create({ stats: LiveMap.create({ visits: LiveCounter.create() }) })); ``` Batch operations result in a message for each operation included in the batch: ### Javascript ``` // Four messages await myObject.get('settings').batch((ctx) => { ctx.set('theme', 'dark'); ctx.set('fontSize', 14); ctx.set('notifications', true); ctx.remove('oldSetting'); }); ``` ## LiveCounter operations Incrementing and decrementing a counter always sends one message: ### Javascript ``` // One message await myObject.get('visits').increment(5); // One message await myObject.get('visits').decrement(3); ``` Creating a `LiveCounter` sends two messages: one to create the new `LiveCounter` object, and one to assign it to the target object: ### Javascript ``` // Two messages: create counter + assign to 'visits' await myObject.set('visits', LiveCounter.create(0)); ``` Creating a counter nested within a `LiveMap` also generates messages for the parent map: ### Javascript ``` // Four messages: // - create visits counter // - create stats map // - create settings map // - assign to 'settings' await myObject.set('settings', LiveMap.create({ stats: LiveMap.create({ visits: LiveCounter.create(0) }) })); ``` Batch operations result in a message for each operation included in the batch: ### Javascript ``` // Three messages await myObject.get('visits').batch((ctx) => { ctx.increment(5); ctx.increment(3); ctx.decrement(2); }); ``` ## Synchronization During initial synchronization and resynchronization, each object on the channel is sent as one or more messages. Large objects, such as maps with many entries, may be split across multiple messages. For example, if a channel contains 10 objects (such as `LiveMap` and `LiveCounter` instances), a client attaching to the channel will receive at least 10 messages during synchronization. Similarly, if a client becomes disconnected and needs to resynchronize, it will receive messages for each object that needs to be synchronized. Only [reachable](https://ably.com/docs/liveobjects/concepts/objects.md?source=llms.txt#reachability) objects are counted. Ably may send [tombstone](https://ably.com/docs/liveobjects/concepts/objects.md?source=llms.txt#tombstones) objects to the client, but these will not count towards your usage. ## Subscriptions Subscribing to updates does not affect the number of messages received by a client. Any client attached to a channel with the `object-subscribe` capability automatically receives all object messages for that channel. Subscribing to updates on an object adds a listener that is called whenever the client receives updates for that object. ## REST API The [LiveObjects REST API](https://ably.com/docs/liveobjects/rest-api-usage.md?source=llms.txt) also counts messages for operations performed. When fetching objects via the REST API, each instance of an [object type](https://ably.com/docs/liveobjects/concepts/objects.md?source=llms.txt#object-types) included in the response is counted as one message. Each operation published via the REST API counts as one message. When creating objects using the `path` field, the server constructs two messages (a create operation and a `MAP_SET` operation to assign it). ## Related Topics - [Objects](https://ably.com/docs/liveobjects/concepts/objects.md?source=llms.txt): Learn how data is represented as objects in Ably LiveObjects - [PathObject](https://ably.com/docs/liveobjects/concepts/path-object.md?source=llms.txt): Learn about PathObject, a path-based API for accessing and manipulating LiveObjects data structures - [Instance](https://ably.com/docs/liveobjects/concepts/instance.md?source=llms.txt): Learn about Instance, a reference to a specific LiveObject instance for direct manipulation - [Operations](https://ably.com/docs/liveobjects/concepts/operations.md?source=llms.txt): Learn how objects are updated by operations in Ably LiveObjects. - [Synchronization](https://ably.com/docs/liveobjects/concepts/synchronization.md?source=llms.txt): Learn how data is synchronized between clients. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt?source=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.