# YouTube Upload-Only + Manual Analytics CSV policy

Use this for AutoShortsBot / TrueTraceShorts YouTube integration.

## Hard scope policy

Only allowed YouTube OAuth scope:

- `https://www.googleapis.com/auth/youtube.upload`

Forbidden scopes:

- `https://www.googleapis.com/auth/youtube.readonly`
- `https://www.googleapis.com/auth/youtube`
- `https://www.googleapis.com/auth/youtube.force-ssl`
- `https://www.googleapis.com/auth/youtubepartner`
- `https://www.googleapis.com/auth/yt-analytics.readonly`
- `https://www.googleapis.com/auth/yt-analytics-monetary.readonly`

If a token contains any additional YouTube/read/analytics scopes, mark it unsafe and do not use it.

## Forbidden data and APIs

`YOUTUBE_RAW_COMMENT_TEXT_ALLOWED = false`

Never read, store, summarize, or analyze raw YouTube comments. Forbidden endpoints:

- `commentThreads.list`
- `comments.list`
- `comments.insert`
- `comments.update`
- `comments.delete`
- `commentThreads.update`

Blocked reason: `Raw YouTube comments are forbidden input.`

No YouTube Analytics API. Analytics is only via sanitized user-exported CSVs.

No YouTube API keys. If `YOUTUBE_API_KEY` or `GOOGLE_API_KEY` is present, warn and ignore it.

## Endpoint allowlist

Upload mode may use only:

- `videos.insert`
- `thumbnails.set`

Note: `thumbnails.set` may still fail with a YouTube 403 if the channel/account is not permitted to upload custom thumbnails (for example channel verification/feature eligibility missing). Treat that as a platform permission issue, not a scope-policy failure; deliver the thumbnail asset for manual Studio upload and retry only after the channel has custom-thumbnail permission.

Important partial-upload pitfall: `videos.insert` can succeed and return a `videoId`, then `thumbnails.set` can fail afterward. In that case the CLI may exit non-zero even though a private video now exists in Studio. Do **not** blindly rerun the upload command, because that can create duplicates. Extract/report the returned video ID or Studio URL from the error/audit if available, write a partial audit noting `videos.insert` succeeded and `thumbnails.set` failed, tell the user to verify privacy/title/description in Studio, and provide the thumbnail asset for manual upload.

Everything else is blocked unless a later explicit policy change is made.

## CLI commands

Auth/token validation:

```bash
python -m autoshorts.cli.youtube_auth_upload_only --validate-only
python -m autoshorts.cli.youtube_auth_upload_only
```

### Headless/manual OAuth callback pitfall

When running OAuth from a remote/headless agent, prefer `run_local_server(..., open_browser=False)` or an equivalent manual auth URL flow so the authorization URL is printed instead of trying to open a desktop browser inside the container.

If the user pastes a callback URL, verify **all** of the following before exchanging the code:

- callback `state` matches the currently generated state;
- callback localhost port matches the current redirect URI;
- callback scope is exactly `https://www.googleapis.com/auth/youtube.upload`;
- the stored PKCE/code verifier belongs to that same auth URL.

Never exchange a pasted code from an older/different OAuth run, even if it has the correct scope. State/port/verifier mismatch means the safe action is to stop the waiting process, generate a new upload-only URL, and ask the user for the fresh final callback URL. Annoying, yes. Correct, also yes.

Prepare hash-bound private upload package; no API write:

```bash
python -m autoshorts.cli.youtube_private_upload_prepare <candidate_id>
```

Dry run; no API write:

```bash
python -m autoshorts.cli.youtube_private_upload_dry_run <candidate_id>
```

Execute only with exact approval command:

```bash
python -m autoshorts.cli.youtube_private_upload_execute <candidate_id> --approval "APPROVED_FOR_PRIVATE_YOUTUBE_UPLOAD <candidate_id> <version> <video_sha256> <posting_pack_sha256>"
```

Real uploads must always be private. Never public, unlisted, scheduled, comment-triggered, or external-text-triggered.

## YouTube description website-link requirement

Every AutoShorts/TrueTraceShorts YouTube description must include the matching website checklist or guide link for that video. Prefer the exact companion page when available, e.g. `https://truetraceshorts.pages.dev/redflags/<slug>/`. For recovery-first videos, use the appropriate guide such as `https://truetraceshorts.pages.dev/already-clicked/`. Do not ship a YouTube upload package with a generic or missing website CTA when a matching page exists.

## TikTok app-review and public-site boundary

If TikTok Developer/App Review text is needed, keep implementation-specific details in private repository documentation, not in public website Terms/Privacy pages. Public pages may mention social platforms generally, but must not disclose TikTok OAuth details, scopes, tokens, draft/upload internals, upload IDs, API endpoints, or internal automation systems.

Internal TikTok review notes may state, without secrets:

- Product: Content Posting API.
- Scope: `video.upload` only.
- No `video.publish`.
- No comments, analytics, messaging, user contact, or viewer personal-data collection.
- Uploaded videos are approved educational shorts for channel-owner review/manual posting.
- Demo should show upload to draft/in-app review, not automatic public publish.

Never commit TikTok client secrets, access tokens, refresh tokens, OAuth callback secrets, or platform credentials.

## Post-private-upload website companion add-on

After every successful private YouTube upload for AutoShorts/TrueTraceShorts, prepare or update the website companion workflow immediately through the Dashboard/WebsiteCompanion service.

Privacy rule: while the YouTube video is still `private`, store the real Shorts URL only as internal/source metadata (`video_url_internal`) and keep public website `videoUrl = null` / `website_link_allowed = false`. The public website must not show a YouTube button/link that normal visitors cannot open. Only set a visible public `videoUrl` after the user makes the video public/unlisted or explicitly sets `website_link_allowed=true`.

Use `references/post-upload-website-companion-sync.md` for the full checklist. Minimum rule: create/update the red-flag guide, start-frame thumbnail, source metadata, and private-link-safe WebsiteCompanion status, then run build/production QA and browser-check the page. Do **not** call YouTube public/read/analytics APIs; the user handles public visibility manually in Studio.

## Post-private-upload response add-on

After every successful private YouTube upload for AutoShorts/TrueTraceShorts, include a separate **TikTok Beschreibung** block for the user to copy manually into TikTok. The user uploads TikTok manually; do not call TikTok APIs.

TikTok description guidelines:

- English, matching the video topic.
- Shorter and more native than the YouTube description: usually 1–3 concise lines plus hashtags.
- Prioritize shares/saves/follows/trust over ad monetization.
- Include the core red flag and safe action.
- Avoid URLs and external calls to click links.
- Hashtags: use 4–6 relevant tags, e.g. `#ScamAlert #DigitalSafety #OnlineSafety #Phishing #EverydayRedFlags`.

## Manual analytics CSV

Import sanitized CSV:

```bash
python -m autoshorts.cli.import_youtube_analytics_csv <path>
```

Learning report:

```bash
python -m autoshorts.cli.youtube_learning_report_from_csv --input <path>
```

Template and docs:

- `data/templates/youtube_analytics_manual_import_template.csv`
- `docs/youtube_manual_analytics_import.md`

Allowed analytics include aggregated metrics such as views, average view duration, shares, comments_count, subscribers_gained, CTR, and the user's own `notes_by_user` summary. Forbidden columns include comments, authors, URLs, links, raw_text, external_text, and unknown external text fields.
