Google Indexing API + Python OAuth2: Part 19 — WordsByEkta🌿
I Wrote 105 Blog Posts. Google Indexed None of Them. Here Is What Finally Worked — Google Indexing API for Blogger Using Python
Estimated Reading Time: 12 minutes
I started this blog in July 2025. I wrote consistently. I fixed my HTML. I submitted my sitemap. I requested indexing manually in Google Search Console — one post at a time, ten per day, the maximum allowed.
A year later, I did a site:wordsbyektaa.blogspot.com search on Google. The only result was a Google support thread from last year — where I had asked why my AdSense was rejected. Not a single blog post. One hundred and five posts, written across twelve months. Zero indexed by Google.
This is the honest story of everything I tried, everything that failed, and the one method that finally worked — explained so clearly that even if you have never opened a terminal window in your life, you can follow this.
Quick Answer
Yes — using the Google Indexing API with Python and OAuth2 authentication, you can submit all your Blogger posts to Google's Indexing API as a recrawl notification in one run. The setup takes about 30 minutes. After that, one command does everything. This guide covers every step — including every error I hit and exactly how I fixed it.
Table of Contents
- What I Tried That Failed
- What Is the Google Indexing API?
- What You Need Before Starting
- Phase 1: Google Cloud Console Setup
- Phase 2: Enable the Right API
- Phase 3: Create OAuth2 Credentials
- Phase 4: Install Python and Libraries
- Phase 5: The Python Script
- Phase 6: Run It — First Time Login
- Phase 7: Automate for Multiple Blogs via RSS
- Every Error I Hit and How I Fixed It
- Daily Limits and What They Mean
- Frequently Asked Questions
- More From This Series
What I Tried That Failed — And Why
Before I tell you what worked, I want to tell you what did not — because every tutorial I found made it sound simple, and none of them mentioned any of this.
| Method | What Happened | Why It Failed |
|---|---|---|
| Manual GSC URL Inspection | 10 requests per day maximum | 105 posts would take 10+ days, and Google still decides when to actually crawl |
| Sitemap Submission | Submitted — status Success | Google discovered posts but marked them "Discovered but not indexed" — 72 of them |
| IndexNow (Bing) | Failed silently | Blogger cannot host the key file required at domain root — covered in Part 13 |
| Service Account for Google Indexing API | ❌ 403 Permission Denied | GSC does not accept service account emails as verified owners for Blogger |
| HTML Unique ID Verification | ❌ Failed | Adding service account unique ID to Blogger theme head tag does not grant GSC ownership |
| OAuth2 Google Indexing API ✅ | 105/105 API submissions accepted | Runs as your personal Google account — GSC ownership recognised instantly |
What Is the Google Indexing API — And What Does It Actually Do?
The Google Indexing API is a tool Google built for websites to notify Google when content is published or updated. Officially, Google says it is meant for job postings and livestream pages. But in practice, many bloggers experiment with it for regular blog posts. In my case, the API accepted the submissions, but that does not mean Google officially supports this use for Blogger.
What it does: it sends Google a URL_UPDATED notification. According to Google, a successful HTTP 200 response means Google may try to recrawl the URL soon. It does not confirm indexing, ranking, or guaranteed crawling. This does not guarantee instant indexing — Google still decides whether to index based on content quality. For me, it at least moved the process from passive waiting to sending Google a direct update notification. For posts stuck in "Discovered but not indexed" for months, this is exactly the nudge they need.
What it does not do: it does not force Google to index anything. It is a signal, not a command.
What You Need Before Starting
- A Google account that is the verified owner of your blog in Google Search Console
- A Windows, Mac, or Linux computer
- Python installed (version 3.7 or above — download from python.org if you don't have it)
- About 30 minutes
- No prior coding experience needed — every command is given exactly as you need to type it
Phase 1: Google Cloud Console Setup
Step 1: Create a Project
- Go to console.cloud.google.com
- Sign in with your Google account — the same one verified in GSC
- Click the project dropdown at the top → click New Project
- Name it anything — for example Blogger Indexing
- Click Create
Phase 2: Enable the Right API
| API Name | Use This? |
|---|---|
| Web Search Indexing API | ✅ YES — this is the correct one |
| Google Search Console API | ❌ NO — this is a different API for reading GSC data |
How to enable it:
- In Google Cloud Console, go to APIs and Services → Library
- Search for Web Search Indexing API
- Click on it → click Enable
- Wait for it to activate — takes about 30 seconds
Phase 3: Create OAuth2 Credentials
OAuth2 credentials are what allow your Python script to run as you — using your personal Google account. This is why it works when the service account did not: Google Search Console recognises you as the verified owner immediately.
Step 1: Configure the Consent Screen
- Go to APIs and Services → OAuth Consent Screen (or Google Auth Platform → Audience)
- Select External → click Create
- Fill in:
- App name: Blogger Indexing (anything)
- User support email: your Gmail
- Developer contact email: your Gmail
- Click Save and Continue through all remaining screens
- On the Test Users screen — click Add Users → add your Gmail → Save
Step 2: Create the OAuth2 Client
- Go to APIs and Services → Credentials (or Google Auth Platform → Clients)
- Click Create Credentials → OAuth 2.0 Client ID
- Application type: Desktop App
- Name: anything — for example BloggerIndexing
- Click Create
- A popup appears — click Download JSON
- Save this file as client_secrets.json in a folder on your computer
client_secrets.json saved on your computer. This is your key. Keep it safe — do not share it or post it publicly.
Phase 4: Install Python and the Required Libraries
Check if Python is installed:
Before checking Python, open the terminal inside your project folder:
First, create one folder for this setup. You can name it Blogger Indexing. Save your client_secrets.json file inside this folder. Later, you will also save OAuth.py in the same folder.
Windows: Open that folder. Right-click on an empty blank area inside the folder, then click Open in Terminal or Open PowerShell window here.
Mac: Open that folder. Right-click the folder, choose Services, then click New Terminal at Folder. If you do not see this option, open Terminal manually, type cd , drag the folder into the Terminal window, and press Enter.
Once the terminal opens in that folder, type:
python --version
If you see a version number like Python 3.10.6 — you are good. If you get an error, download Python from python.org and install it before continuing.
Install the required libraries:
In the same terminal window, paste this command and press Enter:
pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client requests
Wait for it to finish. You will see text scrolling — this is normal. When it stops and you see your cursor again, it is done.
Phase 5: The Python Script
Create a new file in the same folder as your client_secrets.json. Name it OAuth.py. Paste the following script into it exactly as shown:
import pickle
import os
import requests
from xml.etree import ElementTree
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
import time
SCOPES = ['https://www.googleapis.com/auth/indexing']
CLIENT_SECRETS_FILE = 'client_secrets.json'
TOKEN_FILE = 'token.pickle'
# Add all your blog URLs here
BLOGS = [
"https://yourblogname.blogspot.com",
# Add more blogs below — one per line
# "https://yoursecondblog.blogspot.com",
]
def get_credentials():
creds = None
if os.path.exists(TOKEN_FILE):
with open(TOKEN_FILE, 'rb') as f:
creds = pickle.load(f)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRETS_FILE, SCOPES
)
creds = flow.run_local_server(port=0)
with open(TOKEN_FILE, 'wb') as f:
pickle.dump(creds, f)
return creds
def get_all_post_urls():
all_urls = []
for blog in BLOGS:
start = 1
print(f"Fetching posts from {blog}...")
blog_urls = []
while True:
feed_url = f"{blog}/feeds/posts/default?start-index={start}&max-results=25&alt=rss"
try:
response = requests.get(feed_url, timeout=10)
root = ElementTree.fromstring(response.content)
items = root.findall('./channel/item/link')
if not items:
break
for item in items:
blog_urls.append(item.text)
if len(items) < 25:
break
start += 25
time.sleep(1)
except Exception as e:
print(f"Could not fetch {blog}: {e}")
break
print(f"Found {len(blog_urls)} posts")
all_urls.extend(blog_urls)
print(f"\nTotal posts across all blogs: {len(all_urls)}\n")
return all_urls
def index_url(service, url):
body = {"url": url, "type": "URL_UPDATED"}
return service.urlNotifications().publish(body=body).execute()
# Main
creds = get_credentials()
service = build('indexing', 'v3', credentials=creds)
urls = get_all_post_urls()
print(f"Submitting {len(urls)} URLs to Google...\n")
success, failed = 0, 0
for i, url in enumerate(urls, 1):
try:
index_url(service, url)
print(f"[{i}/{len(urls)}] OK: {url}")
success += 1
time.sleep(1)
except Exception as e:
print(f"[{i}/{len(urls)}] FAILED: {url} - {e}")
failed += 1
print(f"\nDone! Success: {success} | Failed: {failed}")
Copy note: If Blogger changes < into text while copying, replace < with the normal less-than sign: <.
https://yourblogname.blogspot.com with your actual blog URL. If you have multiple blogs, add each one on a new line inside the BLOGS list, following the same format. Everything else stays exactly as shown.
BLOGS list. The script automatically builds the RSS feed URL and uses pagination to fetch more than the latest 25 posts. If your blog has under 200 posts, it should usually collect them in one run.
Phase 6: Run It — First Time Login
If your terminal is still open in the same project folder, where you saved client_secrets.json and OAuth.py, simply paste this command and press Enter:
python OAuth.py
The first time you run this, a browser window will open automatically. This is Google asking you to confirm that you allow the script to access your account. Log in with the same Gmail that is verified in GSC and click Allow.
You will see a message: "The authentication flow has completed. You may close this window."
Go back to your terminal. You will see the script running — fetching your posts and submitting them one by one:
token.pickle was also saved in your folder. This stores your login so you never need to go through the browser step again.
Phase 7: Running It Again for New Posts
Every time you publish new posts, open the same folder, right-click on a blank area, choose Open in Terminal, then paste this command and press Enter:
python OAuth.py
No browser login needed. The script reads your token.pickle file and authenticates silently. It fetches all current posts from your RSS feed automatically and submits them. You do not need to update any URL list manually.
token.pickle file or revoke access in your Google account settings.
Every Error I Hit and How I Fixed It
Error 1: 403 Permission Denied
What it means: The account running the script is not the verified owner of the blog in GSC.
Fix: Make sure you log in with the exact Gmail account that is the verified owner in Google Search Console. If you used a service account before, switch to OAuth2 as shown in this guide.
Error 2: Access Blocked During Browser Login
What it means: Your Gmail was not added as a test user in the consent screen.
Fix: Go to Google Cloud Console → Google Auth Platform → Audience → Test Users → Add your Gmail. Then run the script again.
Error 3: Module Not Found
What it means: The Python libraries were not installed correctly.
Fix: Run the pip install command from Phase 4 again. Make sure you are using the same Python version where you ran the install.
Error 4: File Not Found
What it means: The script cannot find your credentials file.
Fix: Make sure client_secrets.json is in the exact same folder as OAuth.py. Check the filename — it must be exactly client_secrets.json with no extra words.
Daily Limits and What They Mean for You
| Limit | Details |
|---|---|
| Daily request limit | 200 URLs per day per Google Cloud project |
| What happens if exceeded | Script will show errors for remaining URLs — simply run again the next day |
| Does submitting the same URL twice cause problems? | No — Google handles duplicate submissions gracefully |
| Does this guarantee indexing? | No — Google still decides whether to crawl, index, or rank the page. The API only confirms that the notification was accepted. |
Frequently Asked Questions
Why did the service account method fail?
Google Search Console does not accept service account emails as verified owners for personal Blogger blogs. OAuth2 works because it runs as your personal Google account — which is already the verified owner in GSC.
Is this officially supported by Google for blogs?
Officially, Google says this API is for job postings and livestream pages. Some bloggers experiment with it, but Google does not officially support the Indexing API for regular blog posts. Use it with that limitation in mind.
Will my posts definitely get indexed after this?
Not guaranteed. In my case, this helped get my URLs accepted for recrawl notification, but Google still decides whether to crawl, index, or rank each page. Google still evaluates content quality. Posts with thin content or duplicate issues may still be skipped. But if your pages were simply waiting to be recrawled, this may help Google notice the update request sooner.
Do I need to run this every time I publish?
Yes — run python OAuth.py after publishing new posts. It takes about 2 minutes and requires no browser login after the first time.
Can I use this for multiple blogs?
Yes — add each blog URL to the BLOGS list in the script. All blogs must be verified under the same Google account in GSC.
What is the token.pickle file?
It stores your login session so you don't need to log in via browser every time. Do not delete it — if you do, the browser login step will happen again on the next run. Do not share it with anyone.
Does this work for Bing too?
No — this submits to Google only. For Bing, see Part 13 of this series which covers the Bing Submission API via Make.com.
More From This Series
🌿 The WordsByEkta Blogger Technical Series
- Blogger is Underrated and I'm Rooting for It: Part 1
- How to Set Up Your Blogger About Me Page: Part 2
- Google Search Console for Bloggers: Part 3
- How to Request Indexing in GSC: Part 4
- Internal Linking for Fast Indexing: Part 5
- Why Isn't My Blog Indexing?: Part 6
- Canonical Tag Fix for Blogger: Part 7
- The AdSense Locked Widget Hack: Part 8
- Use Pingomatic for Faster Indexing: Part 9
- Decoding GSC Reports: Part 10
- Get Traffic from Bing and Yahoo: Part 11
- The AdSense Checklist: Part 12
- Auto Submit Blogger Posts to Bing: Part 13
- Custom Contact Form for Blogger: Part 14
- Extract Blog Post URLs from Sitemap: Part 15
- Open Links in New Tab Blogger: Part 16
- Blogger HTML Mode SEO Mistakes: Part 17
- Google Takeout Blogger Not Working: Part 18
- Google Indexing API for Blogger — What Finally Worked: Part 19 (You are here)
- Is Blogger Worth It Nowadays?: Part 20
- Blogger Mobile HTML Editor Trick for Full Code Copy: Part 21
- Claim Blogger Site on Pinterest (No Custom Domain): Part 22
- Follow.it Email Subscriptions Setup on Blogger: Part 23
- How to Exclude Your Own Visits from GA4 Analytics: Part 24
- Auto Update All Blogger Posts Using Python and Blogger API: Part 25
- My Blog Passed 118/118 AdSense Checks: Part 26
- Ad Networks for Blogger Besides AdSense: Part 27
Comments
Post a Comment