TikTok Approved Our App but Posts Are Still Private

We budgeted two to four weeks and at least one rejection. TikTok approved us in two days, on the first submission.
Then we tried to publish a real post, and it failed.
The approval was real. It just wasn't the approval we thought it was. TikTok runs two separate gates on the Content Posting API, they are named confusingly, and passing the first one does not give you the thing everybody actually wants. We got this wrong in public, so here is the whole thing written down properly.
If you are staring at a SELF_ONLY post wondering what you did wrong: nothing. Start here.
Table of Contents
- Two gates, not one
- The error message that corrected us
- What "unaudited" actually costs
- The review screen is the whole submission
- The five-shot recording
- Never describe your product as unfinished
- Two error messages that cost us a day
- The rules we built before we had to
- Where we actually sit
Two gates, not one
Gate one is App Review. You request products and scopes, you submit, a human checks that a real product exists behind the request. Pass it and your app goes Live and may call the APIs you asked for.
Gate two is the Content Posting API audit. It is a different process with a different queue, and it exists to do exactly one thing: lift the private-viewing restriction.
The trap is that gate one sounds like it finished the job. The portal notification says your app is approved. Your app is Live. Every endpoint answers. You will reasonably conclude you are done.
You are not done. Until gate two passes, TikTok restricts everything your client posts to private viewing mode, regardless of what your app's status says.

The error message that corrected us
Here is what it looks like when you find out:
That came back on a real publish attempt, one day after the approval notification, against a Live app with the right scopes.
Read the error carefully, because it is more specific than it first appears. It is not saying your post will be private. It is saying the account you are posting to must itself be set to private. Those are different claims, and the second one is the one that bites.
An unaudited client cannot post to a public account at all. Not privately, not at all. So the intuitive move after an approval email, flipping your test account public to see the post appear, is precisely the move that breaks posting entirely. You will read the failure as a regression in your own code. It isn't.

What "unaudited" actually costs
Three limits, and it is worth being blunt about what they add up to.
| Limit while unaudited | What it means in practice |
|---|---|
Every post forced to SELF_ONLY | It publishes, only the owner can see it |
| 5 users per 24 hours | Fine for testing, useless for customers |
| Target account must be set to Private | Not just the post. The account. |
Together those mean you do not have a shippable TikTok integration. You have a demo that proves the code path works. Direct posting genuinely functions, you get a post ID back, the video really does land on TikTok, and none of that is worth anything to a customer who wants to be seen.
So do not onboard anyone to TikTok before the audit clears, and do not describe your TikTok support as live. We did the second one for a day and that is why this article exists.

The review screen is the whole submission
Here is the reframe that got us through App Review quickly and is, as far as we can tell, the same thing the audit turns on: they are not really reviewing your integration. They are reviewing one screen, the screen where a human sees the post and presses publish.
TikTok's fear is a tool that fires content into someone's account without them seeing it. Everything they ask for is a way of proving a person was in the loop with real control. So the review screen has to visibly pull from /v2/post/publish/creator_info/query/ and render whatever comes back:
- the creator's avatar and @username, so it is obvious which account you are about to post to
- the privacy levels that account allows, not a hardcoded list of all four
- that account's comment, duet and stitch permissions, greyed out where it disallows them
- the maximum video duration, checked against the actual file
The commonest reason this gets refused, by a distance, is a review screen where the reviewer cannot tell the values came from a live call. A privacy dropdown showing the full generic list, on an account that does not permit all of them, is an instant fail. It looks exactly like a hardcoded mock, because it is one.
The other requirement people miss: the caption must be editable. A read-only caption fails "the creator can review and change it before publishing", even if everything else is perfect.

The five-shot recording
Ours was 138 seconds. One screen recording with a voiceover, and the shot order matters more than the production value.
- The product exists (10s) — the landing page, scrolled slowly. Do not skip this to save time. It does more work than any other shot.
- Connecting an account (20s) — click connect, let the TikTok consent screen sit in frame long enough to read the scopes, approve, land back with the account connected.
- The queue (10s) — the posts waiting for review. Say out loud that nothing reaches TikTok from here.
- The publish screen (45-60s) — the shot the whole thing turns on. Play the video. Name the account. Type into the caption on camera. Open the privacy dropdown so the options are visible. Toggle comment/duet/stitch. Show the commercial disclosure. Show the duration check. Then say, explicitly, that nothing has posted until the button is pressed.
- It is really on TikTok (15s) — switch to the app, show the post live on that account.
Move slower than feels natural. Every required element has to be legible without pausing, and a reviewer who has to squint is a reviewer looking for a reason to bounce you.
We ended on the private post with its "Only you" badge visible, and narrated why it was private: our client is not audited, TikTok correctly forced it, same code path, only the privacy value changes. That was deliberate. It shows the integration works, shows you understand the restriction, and shows you are not trying to route around it.

Never describe your product as unfinished
This is a writing mistake and it costs you the whole submission.
Do not put the words "staged", "pending approval", "not yet launched", "demo environment" or "coming soon" anywhere in the form. Every one of them invites the reviewer to conclude there is no real product behind the integration, and that is the single most common reason for refusal.
We recorded the finished flow, not the current one. At the time of filming, TikTok was the one platform in our stack still costing manual work: the engine dropped a video into the TikTok inbox as a draft and a human opened the app to post it. We did not record that. Filming the draft-and-finish-by-hand dance would have shown a reviewer an unfinished integration, which is exactly what is being screened for.
One more line from the guidelines worth reading twice: a "utility tool to help upload contents to the account(s) you or your team manages" is explicitly unacceptable. If you are building for your own accounts, you have a problem. Be a product with users.

Two error messages that cost us a day
Both undocumented in any useful place, so here they are for the search engines.
file_format_check_failed on photo posts. Photo slideshows reject PNG. Slides have to be JPEG or WebP. Our renderer emitted PNG, so every slideshow died on upload until we converted before uploading. Video was never affected.
url_ownership_unverified in production, after passing in sandbox. URL ownership verification is per environment. Verifying the domain that serves your media on the sandbox property list does nothing for production. You verify twice, once per list, or prod publishing dies on a config screen you already ticked.

The rules we built before we had to
There is a set of Required-UX rules in the Content Sharing Guidelines that you cannot observe while you are unaudited, because forced SELF_ONLY means half of them never fire. They still apply. We built them all rather than wait to be told:
- Privacy has no default. You cannot pre-select a privacy level. The owner must actively choose one.
- No interaction toggle starts checked. Not even the ones the account permits.
- Commercial disclosure is a multiple selection, not a radio. "Your brand" and "Branded content" are independent, both start unchecked, and publishing is blocked until at least one is chosen.
SELF_ONLYis disabled while "Branded content" is on, with TikTok's exact wording as the reason. Not an error after the fact.- Duration is checked against
max_video_post_duration_secfrom the real file, and publish is blocked when it is over. - The Music Usage Confirmation declaration sits above the publish button, switching to the Branded Content Policy wording when branded content is selected.
We enforce every one of those on the server as well as in the UI. A form is not a security boundary, and "our React state prevented it" is not a defence when someone posts straight to your endpoint.
Worth knowing too: you cannot remove the review screen later. Clearing the audit is not permission to automate the human away. Take the screen out and you are risking the integration at re-audit.
Two standing limits that apply whatever your status: TikTok caps posting at roughly 15 posts per creator per 24 hours, and that budget is shared across every API client touching that account, not just yours. And your sandbox tokens belong to your sandbox client, so swapping in production credentials makes every connected account reconnect. Sequence that before you have customers, not after.

Where we actually sit
App Review: passed, two days, first submission. The Content Posting API audit: submitted on 21 August 2026. TikTok says two to four weeks for a decision.
What went in: a request for the "Less than 100" daily publishing-users tier, and a screen recording of the real end-to-end flow rather than a mock. Connect through TikTok's own consent screen. The mandatory per-post review screen, fed live by creator_info/query — creator avatar and username, that account's own privacy options with nothing pre-selected, its comment, duet and stitch permissions, an editable caption, the commercial-content disclosure, the music-usage declaration. An explicit approve. Then the post live on the account's own profile.
That is the same screen described further up, filmed doing the thing it claims to do. If gate two turns on anything, it turns on that.
Until it clears, nothing changes: every TikTok post stays SELF_ONLY, our test account stays private, and we onboard nobody to TikTok. X, Instagram and Bluesky publish fully automatically today. TikTok is pending TikTok, and we are not going to pretend otherwise while the restriction is live.
Everything else in the pipeline runs. We build this for small businesses whose accounts have gone quiet, which is a specific failure with a specific shape — the account dies around week three, and it is a production problem, not a scheduling one.
If you would rather not build any of the above, that is the entire point of ItJustPosts.

Your accounts could be running themselves.
Give ItJustPosts your URL and watch it make the first post.
Start free trial