<
Schedule LinkedIn Post. You write a post, drop it in a queue, and a worker publishes it at the slot you picked. No scrapig.
TRY IT - https://www.unisin.in/
- Sign in with Google or LinkedIn
- Connect LinkedIn once so UniSin can post as that person
- Pick interests and thought leaders (bookmarks for ideas — we cannot follow people for you)
- Set weekly time slots
- Compose, preview, queue, skip a day, or post now
- A background job publishes due posts even if the user’s laptop is off
Google login only opens the app. Publishing still needs Connect LinkedIn.
Until LinkedIn reviews and approves Share on LinkedIn, only you (and LinkedIn test users) can connect posting.
- Open the site → Sign in
- Connect LinkedIn if asked
- Finish onboarding (topics + thought leaders) or skip
- My posts → Edit post schedule → pick times
- Create / New post → write → Add to queue
- Keep the worker (or Vercel cron) running so due posts go out
Posts live in the database. The browser does not need to be open at publish time. The server that runs the worker does.
You are standing up your own copy of UniSin: a Next.js app, a Postgres database, Google login, LinkedIn login + posting, and a small worker that publishes queued posts.
- Node.js 20 or newer (
node -v) - npm (comes with Node)
- Docker Desktop running (for local Postgres). If you already have Postgres, you can skip Docker and point
DATABASE_URLat that server instead. - A Google Cloud project (free) for “Sign in with Google”
- A LinkedIn Developer app for “Sign in with LinkedIn” and Share on LinkedIn
Use port 3000. The sample .env and the OAuth consoles below are written for http://localhost:3000. If Next.js starts on 3001 because 3000 is busy, Google/LinkedIn login will fail until you fix the port or the redirect URLs.
git clone https://github.com/Sameermistrii/Linkdin_Automation.git
cd Linkdin_Automation
npm installnpm install also runs prisma generate so TypeScript can see the database client in generated/prisma.
On Windows, if prisma generate fails with EPERM / file locked, stop npm run dev first, then run npx prisma generate again.
From the project folder:
docker compose up -dThat starts a Postgres 16 container:
- host:
localhost - port:
5432 - user:
postgres - password:
postgres - database:
linkedin_queue
Check it is up:
docker compose psdb should be running. Data is stored in a Docker volume named pgdata, so it survives container restarts.
Not using Docker? Create a Postgres database yourself and put its URL in .env as DATABASE_URL (same shape as Neon: postgresql://USER:PASSWORD@HOST:5432/DBNAME).
cp .env.example .envOn Windows PowerShell:
Copy-Item .env.example .envOpen .env in an editor. Do not commit this file. Fill it as follows.
Leave this as-is if you used Docker in step 2:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/linkedin_queue"
If you use Neon (or any hosted Postgres), paste the connection string they give you, including ?sslmode=require when they tell you to.
Replace the placeholders with long random strings (two different values):
SESSION_SECRET= # signs the login cookie
CRON_SECRET= # password for GET /api/cron/publish (used on Vercel)
Example generator:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Run it twice; paste one into SESSION_SECRET, the other into CRON_SECRET.
Local:
NEXT_PUBLIC_APP_URL=http://localhost:3000
Leave empty on your laptop:
BLOB_READ_WRITE_TOKEN=
Images then save under uploads/ on disk. You only need a Vercel Blob token when the app is hosted on Vercel.
Leave 202608 unless LinkedIn’s docs tell you to bump it.
This is only for Sign in with Google. It does not publish to LinkedIn.
- Open Google Cloud Console → create or pick a project.
- APIs & Services → OAuth consent screen → External (or Internal if you are on a Workspace). Add your email as a test user while the app is in Testing.
- APIs & Services → Credentials → Create credentials → OAuth client ID → type Web application.
- Authorized JavaScript origins:
http://localhost:3000 - Authorized redirect URIs:
http://localhost:3000/api/auth/google/callback
Copy this exactly (no trailing slash). - Create. Copy Client ID and Client secret into
.env:
GOOGLE_CLIENT_ID=....apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-....
GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google/callback
GOOGLE_REDIRECT_URI in .env must be the same string as the redirect you registered in Google.
This is for Sign in with LinkedIn and later Connect LinkedIn (the token used to publish).
- Open LinkedIn Developers → Create app.
- Fill name, LinkedIn Page, and logo. Create.
- Auth tab → Authorized redirect URLs for your app:
http://localhost:3000/api/auth/linkedin/callback
again, exact match, no trailing slash. - Copy Client ID and Primary Client Secret into
.env:
LINKEDIN_CLIENT_ID=....
LINKEDIN_CLIENT_SECRET=....
LINKEDIN_REDIRECT_URI=http://localhost:3000/api/auth/linkedin/callback
- Products tab — request / add:
- Sign In with LinkedIn using OpenID Connect (login)
- Share on LinkedIn (create posts)
Until LinkedIn approves Share on LinkedIn, only the app owner and listed test users can connect posting. Sign-in may work before posting does.
Company Pages need Community Management (separate product, later). Personal profile posting does not.
Still in the project folder, with Docker running and .env saved:
npx prisma migrate deployThis applies every file in prisma/migrations/ to your database. You should see migrations applied, not a connection error.
If it cannot connect: Docker is not running, port 5432 is taken by another Postgres, or DATABASE_URL is wrong.
npm run devWait until it says it is ready, then open http://localhost:3000.
You should see the UniSin landing page. Sign in uses Google or LinkedIn from .env.
If the terminal says it started on 3001, stop it, free port 3000, and start again — or add http://localhost:3001/.../callback in Google, LinkedIn, and change GOOGLE_REDIRECT_URI, LINKEDIN_REDIRECT_URI, and NEXT_PUBLIC_APP_URL in .env to 3001. All three places must match.
The site queues posts. It does not send them to LinkedIn by itself.
Open a new terminal in the same folder (leave npm run dev running):
npm run workerYou should see something like: checking due posts every minute.
That process must stay running on a machine that has internet. If you close it, queued posts wait until it starts again.
-
docker compose psshows the db running (or Neon URL works) -
.envhas real Google and LinkedIn ids/secrets (not empty) - Redirect URLs in Google, LinkedIn, and
.envare identical -
npx prisma migrate deploysucceeded - Browser:
http://localhost:3000loads UniSin - Sign in works
- After LinkedIn sharing is approved (or you are a test user), Connect LinkedIn works
-
npm run workeris running in a second terminal
| What you see | Likely cause |
|---|---|
| Google/LinkedIn “redirect_uri mismatch” | URL in the console ≠ *_REDIRECT_URI in .env, or you are on port 3001 |
| Sign in works, Connect LinkedIn fails | Share on LinkedIn product not added / not approved / you are not a test user |
migrate deploy connection refused |
Docker not running, or DATABASE_URL host/port wrong |
prisma generate EPERM on Windows |
next dev has the Prisma engine locked — stop it, generate, start again |
| Post stays Queued past the slot | Worker is not running, or that machine has no internet |
| Post goes to Errors | LinkedIn token expired, API rejected the post, or media upload failed |
Live site: https://unisin.in
Code: github.com/Sameermistrii/Linkdin_Automation
Stack: Vercel (Next.js) + Neon (Postgres) + Vercel Blob (images). .env stays on your computer. Vercel gets the same keys as environment variables. Never commit .env.
If you cloned from GitHub, git push origin master is enough. GitHub must show the files (not “This repository is empty”).
- Log in at vercel.com with the same GitHub account (
Sameermistrii). - Add New → Project → import Linkdin_Automation.
- Framework: Next.js (auto).
- Build Command:
next build
(postinstall already runs prisma generate. Do not put prisma migrate deploy in the Vercel build — a failed migration like P3009 will block every deploy. Apply schema from your laptop once: npx prisma migrate deploy with Neon’s DATABASE_URL.)
- Do not deploy yet if env vars are empty — add them first (next steps), then Deploy.
- Create a project at neon.tech.
- Copy the connection string.
- In Vercel → Project → Settings → Environment Variables →
DATABASE_URL= that string (includesslmode=requireif Neon shows it).
- Vercel dashboard → Storage → create Blob.
- Copy
BLOB_READ_WRITE_TOKENinto Vercel env.
Keep localhost redirects for local dev. Add these as well:
- Google JavaScript origin:
https://unisin.in - Google redirect:
https://unisin.in/api/auth/google/callback - LinkedIn redirect:
https://unisin.in/api/auth/linkedin/callback
If you also use www:
https://www.unisin.inhttps://www.unisin.in/api/auth/google/callbackhttps://www.unisin.in/api/auth/linkedin/callback
Set for Production (and Preview if you want preview deploys to log in):
| Name | Production value |
|---|---|
GOOGLE_CLIENT_ID |
same as local |
GOOGLE_CLIENT_SECRET |
same as local |
GOOGLE_REDIRECT_URI |
https://unisin.in/api/auth/google/callback |
LINKEDIN_CLIENT_ID |
same as local |
LINKEDIN_CLIENT_SECRET |
same as local |
LINKEDIN_REDIRECT_URI |
https://unisin.in/api/auth/linkedin/callback |
LINKEDIN_API_VERSION |
202608 |
DATABASE_URL |
Neon URL |
BLOB_READ_WRITE_TOKEN |
Blob token |
SESSION_SECRET |
new long random string |
CRON_SECRET |
another long random string |
NEXT_PUBLIC_APP_URL |
https://unisin.in |
Redeploy after saving env vars.
- Vercel → Project → Settings → Domains → add
unisin.inandwww.unisin.in. - Vercel shows DNS records. At your domain registrar (where you bought Unisin.in), set what they ask for, usually:
- A record for
@(apex) → Vercel’s IP, or their ALIAS/ANAME - CNAME
www→cname.vercel-dns.com
- A record for
- Wait for DNS (minutes to a few hours). HTTPS is automatic on Vercel.
vercel.json calls /api/cron/publish once a day at 08:00 UTC (0 8 * * *). Hobby accounts reject every-minute cron (* * * * *).
Queued posts therefore go out at that daily tick (or later if the slot was earlier the same day). For on-the-minute publish: Vercel Pro (then you can set cron back to * * * * *), or run npm run worker on a small always-on VPS using the same DATABASE_URL.
Same model as Buffer or Notion: platform secrets in env, user tokens in the database.
- Someone clicks Continue with Google or LinkedIn
- Google/LinkedIn ask that person for permission
- The server stores their token on their user row
- The worker posts to LinkedIn as that person
| Command | What it does |
|---|---|
npm run dev |
Next.js app |
npm run worker |
Publish due queued posts |
npx prisma migrate deploy |
Apply DB migrations |
npx prisma generate |
Prisma client (generated/prisma) |
Made with 💙 by Sameer Mistri.