DEV Community

Cover image for How I built my open-source Social media scheduling tool... 🤯
Nevo David
Nevo David Subscriber

Posted on

How I built my open-source Social media scheduling tool... 🤯

I published Postiz, my open-source social media scheduling tool, on Reddit, and received much attention.

I guess it was super needed in open-source.
I have received multiple questions from developers on how I built it.

So today, I will take you through the infrastructure and things you need to consider.

Social Media


It all starts with oAuth (oAuth2)

The core of every social media scheduling tool is oAuth. Let me explain.

oAuth is a standard way for different platforms to give you access to their users to perform a limited-scope action.

For example, you can ask Facebook to give you access to post on a user timeline or read their analytics.

oAuth is limited by time but can be refreshed, and the core of every scheduling tool is:

  1. Collect oAuths of different platforms.
  2. Refresh them when needed.
  3. Use them to post on a user timeline.

Since you want to build a generic platform that you can easily add more and more social platforms, you want to build an interface like this (simplified version):

export interface Provider {
  generateAuthUrl(): Promise<GenerateAuthUrlResponse>;
  authenticate(params: {code: string; codeVerifier: string; refresh?: string;}): Promise<AuthTokenDetails>;
  refreshToken(refreshToken: string): Promise<AuthTokenDetails>;
post(token: string, info: MessageInformation): Promise<PostDetails>;
}
Enter fullscreen mode Exit fullscreen mode

generateAuthUrl — This function generates a URL for the user to authenticate on a platform (like LinkedIn). It gives you a code you can later convert to a token to post on a user's timeline.

authenticate - Takes the code of the user, converts it to a token, and creates the user in the database (and saves their token along with the token expiry date)

refreshToken - Takes the user token and expiry date and refreshes it if needed.

post— This function takes the user token and message details and posts them to the user's timeline (it can be a picture, text, video, etc.).

Once you have that, you must catch a user's POST request in an authentication request, map it to the right provider that implements IAuthenticator, and return the generateAuthUrl.

The generateAuthUrl gets a "return URL," which the user will return once they have completed authentication. In that URL, you use the authenticate function.


Scheduling the posting

Platforms mostly will not give you a way to schedule their posts with an API.

Even if they did, it would be hard to manage some who do and some who don't, so it's better to view it as a platform for those who don't.

To do this, you need to implement a queue.

Example: Post to Facebook: "I love Postiz" and process it in 1 week from now.

You have many options for queues.
Some of the most popular are RabbitMQ, SQS, and ActiveMQ

They are perfect when you have tons of jobs, and if you have streaming Petabytes of data, Kafka can probably help.

But in my case, I don't need a "real" queue.

So, I used Redis (Pub-sub). You push some key inside of Redis and add an expiry date. Once the expiry date passes, it triggers Redis and sends a notification (to some service)

There is a great company called BullMQ that simplifies the process with Redis and your app (it's free and fully open-sourced)

Archtecture

Below are "Workers". They are microservices of your application that process and post the "job" on social media.

They are separated because they are smaller than the main application and might need to be scaled depending on your number of jobs.

We call this "Horizontal scaling," as we will need to add more workers as our application grows.


The DB

Usually, you would need to save a post in the DB with multiple statuses—DRAFT, SCHEDULED, COMPLETED, and ERROR—so you can track what happened to it.

In my case, I used Prisma.
Prisma is an ORM that wraps and queries your database using terms like One-to-one, Many-to-many, and one-to-many.

It's a known approach that exists for you in all the languages.
I like it because it keeps a consistent response structure and allows me to change to a different DB in the future (easy migration). I don't have even one raw query in my project (good or bad)

I am using PostgreSQL because it's trending now (according to a StackOverflow survey)

StackOverflow survey

The main thing to be careful about when using SQL is deadlocks. You don't want to update a row from multiple places simultaneously, as this will throw a deadlock, and the update will fail.


Help me out

Postiz is trending on GitHub. It's 100% free, and I will try to give you value as much as possible.

Already crafted a small roadmap from all the requests.

I was hoping you could help me with a star that will help me (well, I can't even describe how much)

Star Postiz

Top comments (79)

Collapse
 
dhruvwill profile image
Dhruvil S Shah

Awesome!
just a small ques, why did you use redis for executing the schedules posts? can I use "cron" for the same ?

Collapse
 
nevodavid profile image
Nevo David

You can run a cron every second to check if something will be posted.
But it feels a bit overkill for me :)

Collapse
 
joaozitopolo profile image
Joao Polo

cron requires extra validation and control of items to be posted. Also, Redis preserves the schedule list and have retry options.
If your service (with cron) loose some event due a shutdown, you'll require an extra effort to detect these loosed events. Also, you'll need an extra effort to retry it.

Collapse
 
nevodavid profile image
Nevo David

Not exactly; you can save it in the DB, for example, and post it on Facebook at 5 pm.
Now you can run a cron every second, check what needs to be scheduled after 5 pm, and don't fail. You will need to lock the job everything, so you want to post it twice (that can be a bit dangerous).

Instead of a cron you might want to run a while(true) event.

Thread Thread
 
dhruvwill profile image
Dhruvil S Shah

I came across this package called "node-schedule" which is similar to schedule in python. I think it fits better to the usecase.
ex.
`const schedule = require('node-schedule');
const { TwitterApi } = require('twitter-api-v2');

// Initialize your Twitter client
const client = new TwitterApi({
appKey: 'YOUR_APP_KEY',
appSecret: 'YOUR_APP_SECRET',
accessToken: 'YOUR_ACCESS_TOKEN',
accessSecret: 'YOUR_ACCESS_SECRET',
});

// Function to post to Twitter
async function postToTwitter(content) {
try {
await client.v2.tweet(content);
console.log('Posted to Twitter successfully');
} catch (error) {
console.error('Error posting to Twitter:', error);
}
}

// Schedule a post
function schedulePost(date, content) {
schedule.scheduleJob(date, function() {
postToTwitter(content);
});
}

// Example usage
const futureDate = new Date(2024, 8, 15, 12, 0, 0); // September 15, 2024, at 12:00:00 PM
schedulePost(futureDate, 'This is a scheduled tweet for a specific date and time!');`

Thread Thread
 
nevodavid profile image
Nevo David

It's a fake scheduler that checks every second on javascript intervals.
It can work, but it's not saving and state, it means that if you close the app and open it again, you will lose all the information.

Thread Thread
 
dhruvwill profile image
Dhruvil S Shah

There must exist a good "real" scheduler for node.
someone suggested "agenda" which syncs with MongoDB

Thread Thread
 
nevodavid profile image
Nevo David

BullMQ with Redis :)

Collapse
 
cmacu profile image
Stasi Vladimirov

Great article, thanks. Some important aspects to make this a real platform include:

  • encryption for securely storing the authO tokens and other sensitive details
  • multi-tenancy. How do you keep data for each account independent from the rest of the accounts? -ability to scale on per tenant based (some tenants post once a month others post 1000 times a day)
  • user roles, permissions and authorization or who can do what in the app
  • integrations with other third parties such as marketing platforms, search engines, content management systems, CRM and ERP applications
  • customizations: the ability to define custom fields, handles, tags, lists, etc and create templates using them
  • templating engine: ability to create templates and adapt them to the various platforms and syntax requirements
  • asset management for image, video and other content
  • AI tools and integrations for suggestions and insights
  • reporting including trends, real time and various filtering

Keep up the good work and you can make this really good.

Collapse
 
oggo profile image
oggo

Very good points!

Collapse
 
nevodavid profile image
Nevo David

Thank you!!

Collapse
 
nevodavid profile image
Nevo David

Awesome, many stuff!
As a single developer, I will need some time.
But I see some really good ones!

Collapse
 
or_bendahan_38b85f8f334a profile image
Or Ben Dahan

Great article and very nice idea 👏
A small scheduler suggestion - for a stateless and scheduled jobs Im using Cloudwatch events that triggers a lambda function. (another option is to use SQS fifo queues between them to achieve atomic operations - not sure if needed in your case at this point but it's an option)

Collapse
 
nevodavid profile image
Nevo David

Yeah, those are more complex infrastructures.
You can also use RabbitMQ or Kafka if you have big streams.
I don't think it's necessary for social media scheduling tools :)

Collapse
 
ashutosh_dev profile image
Ashutosh Pandey

Image description
Responsiveness at its peak !

Collapse
 
nevodavid profile image
Nevo David

Haha!
Wanna help me fix it? :)

Collapse
 
nathandaly profile image
Nathan Daly

I love love the idea <3

Collapse
 
nevodavid profile image
Nevo David

Thank you!

Collapse
 
jeffchavez_dev profile image
Jeff Chavez

Nice. I've been dreaming of this kind of project. Thanks for your effort in sharing this.

Collapse
 
nevodavid profile image
Nevo David

Thank you! :)
Happy Hacking

Collapse
 
yutamago profile image
Yutamago

The main thing to be careful about when using SQL is deadlocks. You don't want to update a row from multiple places simultaneously, as this will throw a deadlock, and the update will fail.

This statement is telling me you don't know much about SQL deadlocks yet.
Try reading more about it and how to avoid them. We're operating a massively huge SQL database and update the same rows in dozens of places simultaneously without seeing a single failed update, so it's at least possible.

Collapse
 
lxm7 profile image
Alex

"Try reading more about it and how to avoid them" - surely this is exactly what he has been doing looking at the post.
"We're operating a massively huge SQL database and update the same rows in dozens of places simultaneously without seeing a single failed update" - this statement isnt telling me much either

Collapse
 
nevodavid profile image
Nevo David

I didn't say it's impossible, but you must be careful with it.
If you don't use workers or your update takes too much time you will get a deadlock.

Collapse
 
st3adyp1ck profile image
Ilya Belous

This is an impressive project! 🎉 It's clear a lot of thought went into building Postiz, and I love how you've shared the technical breakdown so transparently. The approach you took with OAuth2 for handling social media integrations and how you've simplified the provider interface is brilliant! It makes adding new platforms seem much more manageable.

Using Redis for queue management is also a smart move—especially since you don't need a heavyweight solution like RabbitMQ or Kafka. BullMQ is a fantastic choice to complement Redis, and the horizontal scaling with workers makes perfect sense for a tool like this that has the potential to handle many jobs.

I'm also a big fan of Prisma! It really streamlines database interactions, and the flexibility it offers for future DB migrations is a huge plus. Postgres is rock solid, and it's great to hear you're having a smooth experience with it.

Congratulations on all the attention you're getting with Postiz! You've definitely hit a sweet spot in the open-source space. Looking forward to trying it out and contributing a star ⭐ Keep up the great work!

Collapse
 
nevodavid profile image
Nevo David

Thank you 🙏🏻

Collapse
 
shricodev profile image
Shrijal Acharya

Love this project, @nevodavid. 💪
I recently built a similar tool in the CLI for automating Instagram posts. If you'd like to take a look: github.com/shricodev/insta-cron-po...

Collapse
 
nevodavid profile image
Nevo David

Nice Project!

Collapse
 
stefanak-michal profile image
Michal Štefaňák

It is wrong this kind of tool has bussiness potential these days. I'm dissappointed. Anyway nicely done project.

Collapse
 
nevodavid profile image
Nevo David

What do you mean?

Collapse
 
stefanak-michal profile image
Michal Štefaňák

I'm not fan of how social media works. I don't even have meta or X account. A lot of people share a lot of useless stuff. This kind of tool simplify it, which leads to encouraging this behaviour. If you have nothing meaningful to share then don't share.

Thread Thread
 
nevodavid profile image
Nevo David

Cool!
But I think there is still good stuff on social media you just need to follow the right people :)

Thread Thread
 
chetak123 profile image
Ayushman

Really liked how you handled the above comment 👏

Thread Thread
 
nevodavid profile image
Nevo David

👏

Collapse
 
medic_qr_03ae0a9e422b702d profile image
Medic QR

Can I schedule LinkedIn posts with Postiz?

Collapse
 
nevodavid profile image
Nevo David

Of course :)

Collapse
 
medic_qr_03ae0a9e422b702d profile image
Medic QR

Just saw the ui. Amazing work man.
Gonna study the code.

Thread Thread
 
nevodavid profile image
Nevo David

❤️

Collapse
 
crazytonyi profile image
Anthony

Does it support icalendar/caldav? I'm intrigued

Collapse
 
nevodavid profile image
Nevo David

Not sure what are those :)

Collapse
 
crazytonyi profile image
Anthony

It is the protocol for calendar sharing, allowing for things like subscribing to a third party calendar from your Google calendar.
en.wikipedia.org/wiki/ICalendar

Thread Thread
 
nevodavid profile image
Nevo David

So you want to time your social media posts directly from your Google calendar?

Collapse
 
the_greatbonnie profile image
Bonnie

I would love to give Postiz a try.

Collapse
 
nevodavid profile image
Nevo David

Awesome!
Let me know how it goes!

Collapse
 
oggo profile image
oggo

Awesome!

Collapse
 
nevodavid profile image
Nevo David

🙏🏻

Collapse
 
depapp profile image
depa panjie purnama

hey, thanks for sharing open-source tool.
anyway i've built web that can summarize your open-source contributions,
here's the full article: dev.to/depapp/showcase-your-open-s...

Collapse
 
nevodavid profile image
Nevo David

❤️

Some comments may only be visible to logged-in visitors. Sign in to view all comments.