SQO YT Research
YouTube research plugin for WordPress
by Elliott Richmond, Square One Software · github.com/eirichmond/sqo-yt-research · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/eirichmond/sqo-yt-research/archive/refs/heads/main.zipReadme
SQO YT Research
Snapshot YouTube keyword research into custom tables, browse it with DataViews, and export JSON for AI review. Also benchmarks your own channel's videos and suggests new video ideas by comparing the two.
What it does
Keyword research: Runs a YouTube Data API v3 query for a keyword (videos uploaded in the last 7 days, ordered by view count, top 10) and stores the result as a dated snapshot. Each snapshot captures per-video: title, URL, channel, subscriber count, views, likes, duration, category, tags, channel keywords, full description, and publish date.
My Channel benchmarking: Connects to your own YouTube channel via OAuth and syncs its full upload history into a dated stats table, so you can track how each video performs over time. Performance is ranked by views per day since publish, not raw views — this corrects for the age bias in a plain view-count sort (a 2-year-old video will always out-total a 2-week-old one on raw views alone). When connected, syncs also pull averageViewDuration from the YouTube Analytics API, which the public Data API can't provide.
AI suggestions: For any keyword snapshot, generates 10 video ideas (title, description, thumbnail text) by comparing that snapshot's top videos against your own best-performing videos (by views/day), via the Anthropic API.
The admin page (top-level "YT Research" menu) has two tabs — Research for the keyword-snapshot flow above, and My Channel for the benchmark/OAuth/sync flow.
Requirements
- WordPress 6.7+
- PHP 8.2+
- A Google Cloud API key with YouTube Data API v3 enabled (keyword research)
- A Google Cloud OAuth 2.0 Web application client with YouTube Data API v3 and YouTube Analytics API enabled (My Channel benchmarking)
- The
ai-provider-for-anthropicplugin, active and configured with an API key (AI suggestions only — everything else works without it)
Install
- Drop the plugin folder into
wp-content/plugins/and activate (activation creates the custom tables). - The
build/directory ships pre-built. If you're working from source, runnpm install && npm run build. - Open YT Research in the admin menu, expand Settings, paste your Data API key, save.
- Enter a keyword and hit Run query.
My Channel setup (OAuth)
The public Data API can't tell you which of your own videos are actually doing well relative to their age, and it can't return watch-time metrics at all — that needs YouTube Analytics API access via OAuth, scoped to your own channel.
- In Google Cloud Console, on the same project as your Data API key (or a new one): enable YouTube Data API v3 and YouTube Analytics API.
- Under APIs & Services → Credentials, create an OAuth client ID of type Web application — not "Desktop app", which has no redirect URI support and will not work here.
- Add an Authorized redirect URI of
{your site}/wp-json/sqo-yt/v1/channel/oauth/callback.- Google's redirect URI policy rejects reserved/local TLDs (e.g.
.test,.localhost) — onlylocalhost/127.0.0.1are exempt. If your local dev site uses one of these (Laravel Valet's.testincluded), you'll need a temporary reverse proxy tolocalhostfor the OAuth round-trip, and thesqo_yt_research_oauth_redirect_urifilter to point the plugin at it. Production domains aren't affected.
- Google's redirect URI policy rejects reserved/local TLDs (e.g.
- On the My Channel tab, expand Google OAuth settings, paste the Client ID and Secret, save.
- Click Connect channel, complete Google's consent screen (grants read-only YouTube + YouTube Analytics scopes), and you'll land back on My Channel showing "Connected as {channel name}".
- Click Sync my channel to pull your full upload back-catalogue. Re-sync any time to add a new dated stats row to every video's history (views/day is recalculated fresh each sync).
Tokens auto-refresh on use; Disconnect clears them.
Data
{prefix}sqoyt_snapshots— one row per keyword query (keyword, queried_at UTC, video_count){prefix}sqoyt_videos— one row per researched video, keyed to its snapshot{prefix}sqoyt_channel_videos— one row per own-channel video (title, description, tags, category, duration, published_at, first/last synced){prefix}sqoyt_channel_video_stats— one dated row per own-channel video per sync (views, likes, comments, subscribers_at_sync, views_per_day, avg_view_duration_seconds) — the full history behind the "View history" action on the My Channel table{prefix}sqoyt_oauth_tokens— the connected channel's OAuth access/refresh tokens (one row; single-channel only)
Directly queryable, e.g.:
SELECT channel_title, AVG(views) FROM wp_sqoyt_videos GROUP BY channel_title ORDER BY AVG(views) DESC;
SELECT title, views_per_day FROM wp_sqoyt_channel_videos ORDER BY views_per_day DESC LIMIT 10;
REST routes
All under sqo-yt/v1, all require manage_options unless noted:
Research
GET /snapshots— list snapshotsPOST /snapshots— run a query ({ "keyword": "WordPress" })DELETE /snapshots/{id}— delete a snapshot and its videosGET /snapshots/{id}/videos— video rowsGET /snapshots/{id}/export— full JSON payload (what the Download JSON button uses)POST /snapshots/{id}/suggestions— generate 10 AI video ideas from this snapshot vs. your top own videos (errors clearly if the AI plugin is inactive or no benchmark sync has run yet)
My Channel
GET /channel/videos— own-channel videos with latest statsGET /channel/videos/{id}/history— dated stats history for one videoPOST /channel/sync— pull uploads + stats (+ Analytics metrics if connected)GET /channel/oauth/status— connection statusGET /channel/oauth/authorize— starts the OAuth flow (redirects to Google)GET /channel/oauth/callback— public, nomanage_optionsrequired — this is where Google redirects back to; protected instead by a CSRFstatetoken issued to the originating admin userPOST /channel/oauth/disconnect— clears stored tokensGET /channel/suggestions/status— whether the AI plugin is active/available
Quota
- Data API (10,000 units/day free): each keyword query costs ~103 units (search 100, video details 1, channels 1, categories 1) — roughly 97 queries/day. A full channel sync costs ~1 unit per 50 videos (
playlistItems.list) plus 1 unit per 50 videos forvideos.listdetails — negligible even for a large channel. - Analytics API (separate 50,000 units/day pool, doesn't share with Data API): one
reports.querycall per synced video; cost per call is small (single metric, no dimensions), so this isn't a practical limit for a personal-channel sync.
Notes and known trade-offs
order=viewCountranks by lifetime views, not weekly velocity. A slow-burner from 6 days ago can outrank this week's fast riser.- Subscriber counts can be hidden by channels; these store as NULL and display as "hidden".
- Impressions and click-through-rate (YouTube Studio's own "Reach" tab) are not available — confirmed against Google's Analytics API metrics reference and a live 400 error during development.
averageViewDurationis the only own-channel metric this plugin can pull beyond what the public Data API already provides. - AI suggestions are prompts, not data-backed predictions — treat them as a starting point.
- Deleting the plugin (not deactivating) drops all tables and options via
uninstall.php. - The Data API key and OAuth client secret are stored as plain options, readable by any
manage_optionsuser via the REST settings endpoint. Fine for a personal site; restrict the Data API key by API in Google Cloud console regardless.