The LinkedIn Sharing Paradox: Why Testing Social Media Integration is Harder Than It Should Be
Summary
Today I learned that testing LinkedIn sharing integration is like trying to debug code through a one-way mirror while wearing oven mitts.
How LinkedIn Sharing Actually Works
When you share a link on LinkedIn, their crawler immediately visits your URL to scrape Open Graph meta tags:
``...
Today I learned that you test LinkedIn sharing in production, because there is nowhere else to test it.
The mechanism is simple. Share a link and LinkedIn's crawler visits your URL right away, scraping your Open Graph meta tags:
<meta property="og:title" content="Your Article Title">
<meta property="og:description" content="A compelling description">
<meta property="og:image" content="https://yoursite.com/image.jpg">
<meta property="og:url" content="https://yoursite.com/article">
Four tags. Writing them was the fast part, and then the whole evening disappeared into finding out whether they work.
LinkedIn Never Forgets
LinkedIn scrapes your page once and caches what it finds. Then it moves on. Fix a typo in the title afterward? LinkedIn already has its copy and won't be back for a while. No error, no warning. Just a stale preview staring back at you while you clear your browser cache for the third time, which does nothing, because the cache lives on their servers.
You can't get ahead of it locally either, since the crawler can't reach localhost:8000. Your options are all bad: deploy to production and test live (risky), tunnel out with ngrok (one more moving part), use a staging environment (if you have one), or ship it and hope (we've all been there).
The Sites Framework Would Like a Word
Django's Sites framework stores your domain in the database, which is its own little trap:
# This needs to match your actual domain
Site.objects.get_current().domain # 'example.com' vs 'yoursite.com'
If that row is wrong, every absolute URL your site generates is wrong, and your og:url points somewhere that isn't your article. And your local database and your production database each carry their own Site entry, so a preview that behaves in development proves nothing about production.
Escape Hatches
LinkedIn's Post Inspector forces a re-scrape of your URL. It works, mostly, and it sits buried in the developer documentation where nobody casually browsing will trip over it. Bookmark it now.
The cache is also keyed on the exact URL, so /article?v=2 counts as a brand new page. Bump the number, get a fresh scrape. I'm not proud of it.
And check the Site domain before you reach for either trick:
python manage.py shell
from django.contrib.sites.models import Site
Site.objects.get_current().domain # Should be your actual domain
The honest answer, though, is a staging environment with a real domain, because you can't truly test this on localhost no matter how clever you get.
It bugs me that deploying a containerized microservice takes less ceremony than previewing how one link renders on LinkedIn. But the same caching that ate my evening is what lets them serve billions of link previews without melting a data center. LinkedIn built it for LinkedIn, and my debugging session is a rounding error to them.
So here's the procedure, such as it is. A wrong preview means it's cached, so run the Post Inspector or bump ?v=. Wrong after that means the Site domain. Go check the Site domain.