How to use Appify and AgentKit by ScaleKit together.
Appify AgentKit ScaleKit integration how to use together
ScaleKit AgentKit Appify documentation 2025 2026
Apify AgentKit ScaleKit integration tutorial
scalekit apify actor per-user OAuth agentkit cookbook site:docs.scalekit.com OR site:github.com
Apify AgentKit ScaleKit per-user OAuth setup steps code example
npm install -g @apify/cliyoutube.readonly at minimum), click Saveyoutube)notion)apify create notion-youtube-agent -t project_empty
cd notion-youtube-agent
npm install @scalekit-sdk/node openai apify
SCALEKIT_ENV_URL=https://your-env.scalekit.cloud
SCALEKIT_CLIENT_ID=skc_...
SCALEKIT_CLIENT_SECRET=your-secret
.env and run apify login to set your APIFY_TOKEN.src/main.js, initialize the ScaleKit client and decide how to identify each user. Use Apify's built-in userId as the per-user key - this means tokens automatically persist across runs for each Apify account:import { Actor } from 'apify';
import ScalekitClient from '@scalekit-sdk/node';
await Actor.init();
const { userId } = Actor.getEnv();
const scalekit = new ScalekitClient(
process.env.SCALEKIT_ENV_URL,
process.env.SCALEKIT_CLIENT_ID,
process.env.SCALEKIT_CLIENT_SECRET
);
// Per-user: each Apify account connects their own Notion workspace
const notionIdentifier = userId;
// Shared: one YouTube OAuth session used by all runs
const youtubeIdentifier = 'shared-youtube'; // hardcoded, not an input field
OUTPUT:// src/notionAuth.js
import { Actor } from 'apify';
const ACTIVE = 1;
export async function ensureNotionConnected(scalekitActions, identifier, { connectionName }) {
const account = await scalekitActions.getConnectedAccount({ identifier, connectionName });
if (account?.status === ACTIVE) return; // already authorized, proceed
// Generate the magic link and pause the Actor
const { link: magicLink } = await scalekitActions.getAuthorizationURL({
identifier,
connectionName,
});
// Write the auth URL to Actor output so the user can click it
await Actor.setValue('OUTPUT', {
status: 'AWAITING__AUTH',
magicLink,
message: 'Open the magicLink to authorize Notion, then re-run the Actor.',
});
// Poll until the user completes the flow
await pollUntilAuthorized(scalekitActions, identifier, connectionName);
}
AWAITING__AUTH payload with a magicLink to OUTPUT. The user opens that link, completes the OAuth flow, and the Actor picks up automatically.// src/notionTools.js
const token = await scalekitActions.getToken({ identifier, connectionName: 'notion' });
const response = await fetch('https://api.notion.com/v1/search', {
method: 'POST',
headers: {
Authorization: `Bearer ${token.accessToken}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: searchTerm }),
});
// src/agent.js
import { notionTools } from './notionTools.js';
import { youtubeTools } from './youtubeTools.js';
const tools = [...notionTools, ...youtubeTools];
// Standard OpenAI tool-calling loop
while (true) {
const response = await llm.chat({ messages, tools });
if (response.finish_reason === 'stop') break;
const toolResults = await Promise.all(
response.tool_calls.map(call => executeTool(call, scalekitActions))
);
messages.push(...toolResults);
}
apify push
SCALEKIT_ENV_URLSCALEKIT_CLIENT_IDSCALEKIT_CLIENT_SECRETNOTION_DEFAULT_PARENT_PAGE_ID or NOTION_DEFAULT_DATABASE_ID| Event | Default price |
|---|---|
task-completed | $0.05 per run |
tool-call | $0.01 per tool call |
.actor/
actor.json # Apify actor metadata
input_schema.json # Apify Store UI form
output_schema.json # Actor output for web view + dataset
pay_per_event.json # Monetisation event definitions
src/
main.js # Actor entry point - auth + agent
agent.js # Agentic loop (tools + LLM)
llm.js # LLM abstraction (OpenAI-compatible)
notionTools.js # Notion tool definitions + Scalekit executor
notionAuth.js # Magic link + polling auth flow
youtubeTools.js # YouTube API calls via Scalekit
youtubeAuth.js # YouTube magic link + polling auth flow
SCALEKIT_CLIENT_ID/SECRET are operator-level (go in env vars, never in input). Individual users' OAuth tokens are stored by ScaleKit keyed by identifier.userId as the identifier - Using Actor.getEnv().userId means tokens persist across runs automatically per Apify account, with no user-managed input fields.userId. Make this decision per connector.OUTPUT and polling ScaleKit until the connected account becomes active.