rpcflow-api
v1.0.0
Published
Clean Node.js client for Google Flow batchexecute — images, video (text/frames/ingredients), session sync, poll.
Downloads
152
Maintainers
Readme
rpcflow-api
A compact Node.js client for Google Flow (batchexecute): session sync, model/project listing, image generation, video generation (text / frames / ingredients), and polling until media URLs are ready.
Requires Node ≥ 18 (native
fetch). Zero runtime dependencies.
Install
npm install rpcflow-apiRequirements
| Item | Notes |
|------|--------|
| Node.js | >= 18 |
| Cookie | Logged-in cookie string from flow.google.com |
| Activation key (apiKey) | Required on every new RpcFlow(...) — contact the author if you need a key |
| Image reCAPTCHA | Token with ?type=image for createImage / some uploads |
| Video reCAPTCHA | Separate token (without ?type=image) for createVideo |
The library does not read secrets from environment variables. Pass cookie, apiKey, tokens, and optional userAgent yourself.
Quick start
const RpcFlow = require('rpcflow-api');
// or: const { RpcFlow } = require('rpcflow-api');
const cookie = process.env.FLOW_COOKIE; // cookie from flow.google.com
const apiKey = process.env.RPCFLOW_API_KEY; // your activation key (do not hardcode in public repos)
const userAgent =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36';
const flow = new RpcFlow(cookie, { apiKey, userAgent });
// or: new RpcFlow(cookie, apiKey);
// omit userAgent → built-in default is used
// 1) Sync account → at / bl / sid / projectId (+ Bearer when available)
const session = await flow.sync_session();
console.log(session);
// 2) Load session into the instance (you can persist JSON and init later)
flow.init(session);
// 3) Models & projects (pretty output)
console.log(String(flow.models())); // image + video model table
console.log((await flow.projects()).text); // project list
// 4) Create image (needs reCAPTCHA token with type=image)
const imageJob = await flow.createImage({
prompt: 'soft morning light over rice fields',
model: 'NARWHAL', // NARWHAL | GEM_PIX_2 | IMAGEN_3_5
aspectRatio: '16:9',
sessionToken: process.env.IMAGE_TOKEN,
// referenceMediaIds: ['<mediaId>'],
});
console.log(imageJob.images);
// 5) Create text video → poll / wait
const videoJob = await flow.createVideo({
mode: 'text',
prompt: 'gentle nature drone shot',
model: 'abra_t2v_8s',
aspectRatio: '16:9',
sessionToken: process.env.VIDEO_TOKEN, // do NOT reuse the image token
});
const done = await flow.wait(videoJob, { intervalMs: 5000, timeoutMs: 180000 });
console.log(done.videos);Activation key
apiKey is required. Without a valid key the constructor throws and no RPC calls run.
new RpcFlow(cookie, { apiKey: process.env.RPCFLOW_API_KEY });
new RpcFlow(cookie, process.env.RPCFLOW_API_KEY);| Error code | When |
|------------|------|
| API_KEY_REQUIRED | Missing / empty key |
| API_KEY_INVALID | Wrong key |
Keys are distributed privately — they are not documented in this README. Contact the author (see Donate) if you need access.
API
new RpcFlow(cookie, apiKey) / new RpcFlow(cookie, options)
new RpcFlow(cookie, apiKey);
new RpcFlow(cookie, { apiKey });
new RpcFlow(cookie, { apiKey, userAgent: 'Mozilla/5.0 …', hl: 'en' });
new RpcFlow(cookie, { apiKey, session: savedSession });| Arg | Required | Description |
|-----|----------|-------------|
| cookie | yes | Cookie string from flow.google.com |
| apiKey | yes | Activation key |
| userAgent | no | Custom UA; default built into the library (never read from env) |
| session | no | Preloaded session → skip a later init |
| hl | no | batchexecute locale (default en) |
Instance getters: flow.session, flow.userAgent.
await sync_session(opts?) / syncSession()
Scrapes at, bl, sid, projectId from Flow HTML; optionally fetches Labs OAuth ya29….
| Option | Default | Description |
|--------|---------|-------------|
| fetchBearer | true | Try to obtain Labs Bearer |
| flowUrl | Flow home | Override start URL |
| userAgent | instance UA | Override for this call only |
Returns a session object — it is not applied until you call init(session).
init(session)
Apply a session (from sync_session or a saved JSON file). Requires session.at.
models(opts?)
Wire-safe model catalog (no network).
flow.models(); // pretty string (safe to console.log)
flow.models({ pretty: false }); // { image, video, all }
flow.models({ kind: 'image' | 'video' | 'all' });await modelsLive()
Hits live RPC HTrJv and returns raw results plus the known catalog.
await projects(opts?)
const { projects, text } = await flow.projects();
flow.init({ ...flow.session, projectId: projects[0].id });If the instance has no projectId yet, the first project id is stored automatically.
await credits()
Raw credits RPC (nzlxg).
await uploadImage({ imageBytes, mimeType?, fileName?, sessionToken?, projectId?, variant? })
Upload a reference / frame image.
| Field | Notes |
|-------|--------|
| imageBytes | Base64 or data: URL |
| mimeType | Default image/png |
| sessionToken | Image captcha when required |
| projectId | Falls back to session |
Returns { ok, mediaId, projectId, variant, … }.
await createImage({ prompt, sessionToken, model?, aspectRatio?, seed?, referenceMediaIds?, projectId? })
| Field | Default / notes |
|-------|-----------------|
| prompt | required |
| sessionToken | required (image reCAPTCHA) |
| model | NARWHAL (GEM_PIX_2, IMAGEN_3_5) |
| aspectRatio | 16:9 (1:1, 9:16, 4:3, 3:4, …) |
| seed | random int32-safe |
| referenceMediaIds | up to 10 media ids from uploadImage |
Returns { kind:'image', done, images:[{ mediaId, url, … }], request, … }. URLs are usually ready immediately — poll / wait are optional.
await createVideo({ prompt, sessionToken, model, mode?, … })
| Field | Notes |
|-------|--------|
| prompt | required |
| sessionToken | required (video reCAPTCHA) |
| model | required — see flow.models({ kind:'video' }) |
| mode | text (default) | frames | ingredients |
| aspectRatio | 16:9 | 9:16 | 1:1 |
| startMediaId / endMediaId | frames mode |
| referenceMediaIds | ingredients mode (1–7) |
| projectId | falls back to session |
| mode | Extra fields |
|--------|----------------|
| text | — |
| frames | startMediaId, optional endMediaId |
| ingredients | referenceMediaIds (1–7) |
Returns { kind:'video', operations, record, poll, videos, … }. Call poll / wait until videos[].url appears.
await poll(job) / await pollVideo(job) / await pollImage(job)
One status tick. poll routes by job.kind.
Video tick chain: jwpduf → as29s → uurnC → Zzl0ze.
await wait(job, { intervalMs?, timeoutMs? })
| Option | Default |
|--------|---------|
| intervalMs | 5000 |
| timeoutMs | 180000 |
Polls until a video URL appears, the job fails, or the timeout is hit. For image jobs, returns immediately if already done.
snake_case aliases
sync_session, create_image, create_video, upload_image, poll_video, poll_image, …
Escape hatch
await flow.rpc('HTrJv', []);Persist session
const fs = require('fs');
const session = await flow.sync_session();
fs.writeFileSync('session.json', JSON.stringify(session, null, 2));
// later
const saved = JSON.parse(fs.readFileSync('session.json', 'utf8'));
const flow2 = new RpcFlow(saved.cookie, { apiKey: process.env.RPCFLOW_API_KEY });
flow2.init(saved);Frames / Ingredients examples
const up = await flow.uploadImage({
imageBytes: fs.readFileSync('frame.jpg').toString('base64'),
mimeType: 'image/jpeg',
sessionToken: process.env.IMAGE_TOKEN,
});
// single start frame
await flow.createVideo({
mode: 'frames',
prompt: 'slow push in',
model: 'abra_t2v_8s',
startMediaId: up.mediaId,
sessionToken: process.env.VIDEO_TOKEN,
});
// start + end
await flow.createVideo({
mode: 'frames',
prompt: 'morph start to end',
model: 'abra_t2v_8s',
startMediaId: startId,
endMediaId: endId,
sessionToken: process.env.VIDEO_TOKEN,
});
// ingredients
await flow.createVideo({
mode: 'ingredients',
prompt: 'match these references',
model: 'abra_t2v_8s',
referenceMediaIds: [id1, id2],
sessionToken: process.env.VIDEO_TOKEN,
});Common errors
| Code | Meaning |
|------|---------|
| API_KEY_REQUIRED / API_KEY_INVALID | Missing or wrong activation key |
| SESSION_SYNC_FAILED / AT_MISSING | Cookie expired / not logged in |
| NOT_INITIALIZED | Call sync_session + init first |
| PROJECT_REQUIRED | No projectId on session or request |
| IMAGE_TOKEN_REQUIRED / VIDEO_TOKEN_REQUIRED | Missing captcha token |
| PUBLIC_ERROR_UNUSUAL_ACTIVITY | Anti-bot — mint a new token, slow down requests |
| PUBLIC_ERROR_USER_QUOTA_REACHED | Quota exhausted |
| INVALID_ARGUMENT | Bad payload / model / token |
| MODEL_NOT_SUPPORTED | Model not in the catalog |
| UPLOAD_FAILED | All upload payload variants rejected |
| RECORD_REQUIRED | pollVideo needs CAE record from createVideo |
Package layout
rpcflow-api/
package.json
README.md
src/
index.js # exports
RpcFlow.js # class API
license.js # activation gate
models.js # catalog + pretty print
errors.js
utils.js
auth/ # cookie → at/bl/sid + Bearer
client/ # batchexecute + parse
image/ # payloads ogiZ0b / maseQ
video/ # payloads YhhmEf / eb1hJf / nprQif / MZZa6b + pollWire shapes are measured from the Flow frontend; update payloads under src/image / src/video when Google changes RPCs.
Publish to npm
cd rpcflow-api
npm login
npm publish --access publicLicense
MIT
Donate
If this library helps you, consider supporting via PayPal:
PayPal: [email protected]
