TikTok
Prepare TikTok creator choices and publish verified media URLs with Social SDK, covering consent, privacy settings, drafts, and processing checks.
The direct TikTok adapter accepts an existing access token and creator openId. The server package also provides tiktokOAuth for TikTok Login Kit web authorization and creator discovery. OAuth consent does not replace the adapter’s creator preview and publish consent requirements.
Setup
Connect the creator
Use ConnectionManager with tiktokOAuth to bind the callback to the authenticated tenant,
show the discovered creator, and persist credentials through an encrypted credentialSink. Its
default scopes are user.info.basic and video.publish, sent comma-delimited; refresh with
refreshOAuthToken("tiktok", ...) and persist any rotated refresh token.
Verify media origins
The adapter uses verified PULL_FROM_URL media origins. List every host you will publish from
in verifiedMediaOrigins and verify them with TikTok.
Configure the adapter
Construct the backend with the token, openId, and verified origins.
import { createSocial, connectedAccountRef } from "@opencoredev/social-sdk";
import { tiktok } from "@opencoredev/social-sdk/tiktok";
const social = createSocial({
backend: tiktok({
auth: {
accessToken: process.env.TIKTOK_ACCESS_TOKEN!,
openId: process.env.TIKTOK_OPEN_ID!,
},
verifiedMediaOrigins: ["https://media.example.com"],
}),
});
const account = connectedAccountRef({
backend: "default",
platform: "tiktok",
accountId: process.env.TIKTOK_OPEN_ID!,
});
Examples
Fetch creator info before publishing
TikTok requires showing the creator a preview of their current settings and letting them choose from the returned privacy levels. Creator information must be bound to the same backend and account.
const creatorInfo = await social
.native("default", { acknowledgeUnsafe: true })
.creatorInfo(account, {
correlationId: "creator-preview",
retryBudget: { maxAttempts: 1, maxElapsedMs: 10_000 },
authorization: { tenantId: "tenant", principalId: "user" },
});
// Render creatorInfo.privacyLevels and let the creator choose one of the returned values.
Publish a video
const result = await social.posts.publish({
targets: [
{
account,
options: {
consentGiven: true,
creatorInfo,
privacy: "PUBLIC_TO_EVERYONE",
disableComments: false,
disableDuet: false,
disableStitch: false,
brandedContent: false,
ownBrand: false,
photoCoverIndex: 0,
},
},
],
content: {
text: "A creator-approved caption",
media: [
{
kind: "video",
source: { kind: "https-url", url: "https://media.example.com/video.mp4" },
durationSeconds: 8,
},
],
},
});
Publish a photo carousel
The adapter supports one video or 1–35 photos. photoCoverIndex selects the cover image.
const result = await social.posts.publish({
targets: [
{
account,
options: {
consentGiven: true,
creatorInfo,
privacy: "PUBLIC_TO_EVERYONE",
disableComments: false,
disableDuet: false,
disableStitch: false,
brandedContent: false,
ownBrand: false,
photoCoverIndex: 1,
},
},
],
content: {
text: "Photo set",
media: [
{ kind: "image", source: { kind: "https-url", url: "https://media.example.com/1.jpg" } },
{ kind: "image", source: { kind: "https-url", url: "https://media.example.com/2.jpg" } },
],
},
});
Reconcile the publish ID
The initial publish call returns accepted with a publish_id. Reconcile through posts.getDelivery: processing states remain processing, a confirmed failure remains failed, and a public ID is required before reporting published.
const outcome = result.outcomes[0];
if (outcome?.delivery) {
const delivery = await social.posts.getDelivery(outcome.delivery);
console.log(delivery.state); // processing | published | failed | unknown
}
Draft/inbox and public posting have different upstream review and audit requirements; the SDK does not claim approval or silently change privacy.
Receive webhooks
Pass the app client secret as webhookSecret. adapter.webhooks.verify checks TikTok-Signature and rejects timestamps more than 300 seconds old; set webhookToleranceSeconds to change the window, because TikTok does not publish one. Publish events decode to publication.updated with the publish_id as backendRecordId, and authorization.removed decodes to account.updated. See Process webhooks.
Native operations
The typed native module adds the inbox/draft upload path, own-video listing with display fields, and an explicit publish-status query. Post metrics from social.analytics.getPostMetrics read like, comment, share, and view counts through the Display API video query and require video.list; account metrics require user.info.stats. Polling is caller initiated and bounded; the SDK does not run background polling. Comments and direct messages remain platform limits for standard Content Posting and Display API apps.
Limits and requirements
- Explicit privacy and interaction choices are required on every publish, and captions are validated against the format limit.
- Published posts cannot be edited. The Content Posting API sets the caption, privacy, and interaction settings only when a post is initialized, so
posts.updateis declaredunsupported-by-platform. - Keep tokens server-side and treat media URLs, creator data, and publish IDs as sensitive.
- Repository evidence is offline contract and mocked transport coverage; no TikTok app or creator account has been live-verified.
TikTok’s content sharing guidelines describe creator preview, consent, privacy, and app-audit requirements.