URL: /code/integrations/youtube · Id: `page:/code/integrations/youtube`

# YouTube

> Your agents upload your walkthroughs with title, captions and thumbnail, publish them on schedule, and answer every comment as you.

Your agents upload your walkthroughs with title, captions and thumbnail, publish them on schedule, and answer every comment as you.

```text title="Run it · Ask"
Upload my rent-tracking walkthrough as a public video with automatic captions, and show me how it will read.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Post.publish({ handle: 'youtube:leaseline', format: 'video', title: 'Track rent for 50 units without a spreadsheet', file: 'files/walkthrough-rent', captions: 'auto', status: 'public' })
```

```json title="Run it · Response"
{
  "$type": "Post",
  "mode": "try",
  "stored": false,
  "venue": "youtube",
  "status": "public",
  "title": "Track rent for 50 units without a spreadsheet",
  "titleLength": 45,
  "descriptionBytes": 812,
  "captions": "en, automatic",
  "thumbnail": "set from files/walkthrough-rent at 0:42",
  "checks": {
    "title": "within 100",
    "description": "within 5,000 bytes",
    "tags": "within 500"
  }
}
```

- **Connect:** Sign in once, 3 grants
- **Runs through:** [Your account](/code/integrations#three-ways)
- **First run:** See which videos rank for your problem, about 0.03¢
- **Sites:** [YouTube](/venues#youtube)

## Connect once
1. Call `Integration.connect` with `system: 'social'` and `venue: 'youtube'`, then open the `connectUrl` it returns and sign in as the Google account that owns your channel.
2. Approve the three grants Google lists, then pick the channel if the account holds more than one.
3. Call `Handle.connect` to bind the channel as your account.

| Grant | What it unlocks | Scope |
| --- | --- | --- |
| Upload | New videos, with title, description, tags and privacy | `https://www.googleapis.com/auth/youtube.upload` |
| Manage videos and comments | Captions, thumbnails, playlists, edits and takedowns, and replies to comments | `https://www.googleapis.com/auth/youtube.force-ssl` |
| Read your channel | Each video’s views, likes and comments | `https://www.googleapis.com/auth/youtube.readonly` |

| To | Do this |
| --- | --- |
| Pause | `Integration.pause` stops every call through Google at once and keeps the token; `Integration.resume` picks up from the same cursor. |
| Reconnect | `Integration.reconnect` returns a fresh `connectUrl` that lasts one hour, and keeps the Integration's id and cursor, so nothing imports twice. |
| Disconnect | `Integration.revoke` revokes the token with Google; every record it brought in stays in your records. |

## What your agents do
| Ask | Verb | Runs through | Price |
| --- | --- | --- | --- |
| Upload this walkthrough with its title, description, captions and thumbnail. | [`Post.publish`](/code/apps/social/publish) | Your account | Free |
| Upload it now and make it public Tuesday at 9:00. | [`Post.schedule`](/code/apps/social/schedule) | Your account | Free |
| Reply to each new comment on my videos. | [`Conversation.answer`](https://startupbuilder.dev/business/nouns/conversation/answer) | Your account | Free |
| Take down the old pricing video. | [`Post.withdraw`](https://startupbuilder.dev/business/nouns/post/withdraw) | Your account | Free |
| Show me each video’s views and comments this month. | [`Metric.query`](/code/apps/analytics-and-experiments/query) | Your account | Free |

Calls on your own account are free.

Reading this site’s public data needs no account: [`Keyword.search`](/code/data/keywords/search) is a Data call (the [three ways a call runs](/code/integrations#three-ways)).

## What it holds
| Noun | The account’s object | When | Which side leads |
| --- | --- | --- | --- |
| [Post](https://startupbuilder.dev/business/nouns/post) | `video` | Your agent uploads | Your records |
| [Message](https://startupbuilder.dev/business/nouns/message) | `commentThread` | Someone comments, or your agent replies | The account |
| [Prospect](https://startupbuilder.dev/business/nouns/prospect) | `channel` | A commenter who fits asks how it works | Your records |

## Events and webhooks
| Direction | Event |
| --- | --- |
| Emits | `Post.published`, `Post.scheduled`, `Post.withdrawn`, `Message.created` |
| Hears `PubSubHubbub channel feed` | Becomes `Post.published` |

Any Event can wake a Workflow, and a Watch delivers it to your endpoint, signed ([Events and webhooks](/code/events)).

## Limits
| What | Limit | Call |
| --- | --- | --- |
| A scheduled video | Uploads private and goes public at its time; YouTube allows a time only on a video never published before | [`Post.schedule`](/code/apps/social/schedule) |
| Upload quota | YouTube meters uploads a day; an upload past the day’s quota refuses with `quota-reached` and runs after the reset at midnight Pacific | [`Post.publish`](/code/apps/social/publish) |
| Custom thumbnails and videos over 15 minutes | Need a verified channel; the agent checks before it uploads and says which step is missing | [`Post.publish`](/code/apps/social/publish) |
| Comments | Read every 30 minutes, since YouTube sends no webhook for comments | Every call |

## Start here
| Move | The rule |
| --- | --- |
| Structure | One channel and one walkthrough a week, each answering one search your buyers type, titled with that search. |
| Budget | No spend: about 2 hours of your time a video, cut into 3 Shorts and one post, so each recording feeds four places. |
| Creative | Show the result in the first 15 seconds, then the steps on screen; captions on every video, and a description whose first line repeats the search. |
| Kill rule | Retitle a video once if it has under 100 views from search at 30 days; after 8 videos with no signups from YouTube, move the hours to your next Play. |

| Benchmark | Source |
| --- | --- |
| Title 100 characters, description 5,000 bytes, tags 500 characters | YouTube Data API |
| Judge a video at 30 days by views from search, not by subscribers | Our planning number |
| 8 videos before you judge the channel | Our planning number |

## Field map
| Our field | YouTube’s field | Notes | Calls |
| --- | --- | --- | --- |
| `Post.title` | `snippet.title` | 100 characters, no < or > | [`Post.publish`](/code/apps/social/publish), [`Post.schedule`](/code/apps/social/schedule) |
| `Post.body` | `snippet.description` | 5,000 bytes, so accented letters count double | [`Post.publish`](/code/apps/social/publish), [`Post.schedule`](/code/apps/social/schedule) |
| `Post.tags` | `snippet.tags` | 500 characters in all, commas included | [`Post.publish`](/code/apps/social/publish), [`Post.schedule`](/code/apps/social/schedule) |
| `Post.publishAt` | `status.publishAt` | Sent with status.privacyStatus private | [`Post.schedule`](/code/apps/social/schedule) |
| `Post.status` | `status.privacyStatus` | public, unlisted or private; public when none is set | [`Post.publish`](/code/apps/social/publish) |

## What try does here
Checks the file, title, description and tags against YouTube’s limits and returns the video page as it will read; nothing uploads and no quota is spent.

## How long a connection lasts
A connection lasts until you revoke it in your Google Account; Google also ends a grant left unused for six months, and every call your agents make counts as use.

The platform asks you to reconnect 7 days before it runs out; until you do, a call that needs it refuses with [`needs-reauth`](/code/refusals#needs-reauth).

## Formats
| Site | Format | Size | Limits |
| --- | --- | --- | --- |
| [YouTube](/venues#youtube) | Video | None. | Title 100 characters; description 5,000 bytes; tags 500 characters in all |

## Plays and strategies
| Kind | Where |
| --- | --- |
| Plays | [Video ladder](/plays/video-ladder), [Developer relations](/plays/developer-relations), [Events and webinars](/plays/events-and-webinars), [Reuse what you already published](/plays/archive-repurposing), [Sponsorships](/plays/sponsorships) |
| Strategies | [Launch and search](/strategy/launch-and-search) |

## Used by
No Workflow, agent task or Service acts through it yet: your agents call it directly.

## Reference

| Call | Path | Price |
| --- | --- | --- |
| [`Post.publish`](/code/apps/social/publish) | `POST /posts/publish` | Free |
| [`Post.schedule`](/code/apps/social/schedule) | `POST /posts/schedule` | Free |
| [`Conversation.answer`](https://startupbuilder.dev/business/nouns/conversation/answer) | `POST /conversations/answer` | Free |
| [`Post.withdraw`](https://startupbuilder.dev/business/nouns/post/withdraw) | `POST /posts/withdraw` | Free |
| [`Metric.query`](/code/apps/analytics-and-experiments/query) | `POST /metrics/query` | Free |