Google Sheets Stream component
The
google-sheets-streamcomponent polls a range of a Google Sheets spreadsheet and emits the rows that were appended since the previous poll.
Scheme: google-sheets-stream: · Crate: cameleer-cloud · Cargo feature: cloud ·
Consumer: yes · Producer: no · Apache Camel: Google Sheets Stream
When to use it
- Trigger a route when someone adds a row to a shared sheet: a new order, a support request, a task for an AI agent to work on.
- Feed rows entered by a business team into a database, a queue or an API.
- Run a "sheet as inbox" workflow at the edge without a webhook or a public URL (it only polls).
URI format
google-sheets-stream://spreadsheetId?range=Sheet1!A2:D1000[&options]The spreadsheet id is the path (or the spreadsheetId option). range is required; the endpoint
fails to start without it.
Example
Every 30 seconds, read Orders!A2:D1000 and send each new row on its own, as JSON, to the log.
The first poll emits all rows already in the range.
- route:
id: new-orders
from:
uri: "google-sheets-stream://{{env:SHEET_ID}}?range=Orders!A2:D1000&splitResults=true&delay=30000"
steps:
- log: "row ${header[CamelGoogleSheets.valueIndex]}: ${body}"
- marshal:
json: {}
- to: "log:new-orders"With splitResults=true the body of each exchange is one row, for example
["1042","Ada","3","shipped"], and CamelGoogleSheets.valueIndex is its 1-based row number
inside the range. Without it, one exchange per poll carries all new rows as a ValueRange map
(range, majorDimension, values).
Rust DSL
ctx.add_routes(|b| {
b.from("google-sheets-stream://{{env:SHEET_ID}}?range=Orders!A2:D1000&splitResults=true&delay=30000")
.log("row ${header[CamelGoogleSheets.valueIndex]}: ${body}")
.marshal("json")
.to("log:new-orders");
})?;How new rows are detected
The consumer remembers how many rows the range had at the previous poll and emits only the rows after that position. If rows are deleted so that the range becomes shorter, it starts counting again from the new end. Edits to rows that were already emitted are not detected.
This differs from Apache Camel, whose consumer emits the whole range on every poll. Use a filter or an idempotent consumer there; with Cameleer you get only the appended rows. The position is kept in memory, so after a restart the first poll emits the whole range again.
Options
| option | default | description |
|---|---|---|
spreadsheetId | path | The spreadsheet id (instead of the path). |
range | A1 range to read, for example Orders!A2:D1000. Required. | |
splitResults | false | One exchange per new row instead of one per poll. |
majorDimension | ROWS | ROWS or COLUMNS. |
valueRenderOption | FORMATTED_VALUE, UNFORMATTED_VALUE or FORMULA. | |
delay | 500 | Milliseconds between polls (scheduled poll consumer options such as initialDelay (default 1000), repeatCount and backoffMultiplier also apply). |
serviceAccountKey | GOOGLE_APPLICATION_CREDENTIALS | Service account JSON key (file:path, path or inline JSON). |
clientId, clientSecret, refreshToken | OAuth user credentials (refresh-token flow). | |
accessToken | A fixed OAuth access token. | |
delegate (alias subject) | User to impersonate with domain-wide delegation. | |
scopes | https://www.googleapis.com/auth/spreadsheets | Comma separated OAuth scopes. |
uriEndpointOverride + overrideEndpoint=true | Base URL of an emulator or proxy. |
The other shared Google options (tokenServerUrl, useMetadataServer, authenticate,
proxyHost, proxyPort, trustAllCertificates) work as on the
google-sheets page. includeGridData and maxResults are accepted
and ignored.
Message headers
| header | direction | description |
|---|---|---|
CamelGoogleSheets.spreadsheetId | out | The spreadsheet id. |
CamelGoogleSheets.range | out | The range returned by the API (for example Orders!A2:D1000). |
CamelGoogleSheets.majorDimension | out | ROWS or COLUMNS. |
CamelGoogleSheets.valueIndex | out | With splitResults=true: the 1-based row number within the range. |
Header names contain dots, so read them in Simple with the bracket form:
${header[CamelGoogleSheets.valueIndex]}.
Run it with Docker
docker run --rm \
-e SHEET_ID=1AbC...xyz \
-e GOOGLE_APPLICATION_CREDENTIALS=/secrets/key.json \
-v "$PWD/key.json:/secrets/key.json:ro" \
-v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/new-orders.camel.yamlCommon questions
How do I trigger a route when a row is added to a Google Sheet?
Use google-sheets-stream://<spreadsheetId>?range=...&splitResults=true. Each appended row
arrives as one exchange with the row as a list.
Why do I get all rows again after a restart?
The last row position is kept in memory only. Skip the first batch with a filter, or record processed ids with an idempotent repository.
Can I watch several tabs?
Use one route per range, each with its own google-sheets-stream endpoint.
Related
- google-sheets: read and write values.
- Idempotent consumer
- Apache Camel Google Sheets Stream component
Found a problem?
If something on this page doesn't match what Cameleer does, or you hit a bug while building
with it, please help fix it, whether you are a person or a coding agent:
open an issue that describes what you saw,
then fork the repository, fix it, add or update a test, run cargo test --workspace, and open
a pull request. CONTRIBUTING.md
explains the ground rules.