iToverDose/Software· 27 MAY 2026 · 16:06

Self-Host Your Social Media Scheduler with Laravel in 2024

Discover how one developer built an open-source tool to schedule posts across ten networks without relying on third-party servers. Learn the technical architecture, token management, and scheduling techniques used to create a fully self-hosted alternative.

DEV Community3 min read0 Comments

Building a reliable social media posting routine often means wrestling with third-party schedulers that demand control over your content, analytics, and credentials. Frustrated by this trade-off, one developer decided to create their own solution—an open-source, self-hostable scheduler that puts users back in charge.

The result is TryPost, a Laravel-powered tool that supports ten major networks including X, LinkedIn, Instagram, TikTok, and Threads. Unlike commercial platforms, TryPost runs entirely on your own server, ensuring privacy and full data ownership. Here’s how it works under the hood.

A Unified Platform for Ten Different Networks

The biggest challenge in building a social media scheduler isn’t the interface—it’s the fragmented APIs, inconsistent limits, and unique requirements across platforms. X enforces a 280-character cap. LinkedIn allows up to 3,000 characters. Instagram won’t publish without an image. Threads and Bluesky use entirely different protocols. Integrating all of this directly into the application would create a tangled mess.

To avoid this, the developer centralized platform-specific logic in a single PHP enum. Each network is represented as a case, with methods defining its rules:

enum Platform: string
{
    case X = 'x';
    case LinkedIn = 'linkedin';
    case Instagram = 'instagram';
    case Threads = 'threads';
    case Bluesky = 'bluesky';
    // Additional cases omitted for brevity

    public function maxContentLength(): int
    {
        return match ($this) {
            self::X => 280,
            self::LinkedIn => 3000,
            // Additional cases omitted for brevity
        };
    }

    public function queue(): string
    {
        return "social-{$this->value}";
    }
}

Each network also gets its own dedicated Publisher class responsible for API communication. A service locator dynamically selects the correct publisher at publish time, keeping the core scheduling logic clean and platform-agnostic:

private function publisher(): SocialPublisher
{
    return match ($this->postPlatform->platform) {
        Platform::X => app(XPublisher::class),
        Platform::LinkedIn => app(LinkedInPublisher::class),
        Platform::Instagram => app(InstagramPublisher::class),
        // Additional cases omitted for brevity
    };
}

This design means adding support for a new network involves just three steps: extending the enum, writing a new publisher class, and registering it in the service locator. The calendar, composer, and scheduler remain unchanged.

Securing OAuth and Managing Token Refreshes

Connecting accounts relies on OAuth, with Laravel Socialite handling the authentication flow for most platforms. Custom providers were added for networks like Instagram, which require long-lived tokens.

Token security is critical, so sensitive fields are stored encrypted in the database using Laravel’s built-in casting:

protected function casts(): array
{
    return [
        'access_token' => 'encrypted',
        'refresh_token' => 'encrypted',
        'token_expires_at' => 'datetime',
        'scopes' => 'array',
    ];
}

The real hurdle, however, was preventing refresh token races. Some platforms invalidate old refresh tokens immediately upon use, meaning multiple scheduled posts attempting to publish simultaneously could inadvertently disconnect an account. The solution involved two key safeguards.

First, only attempt to refresh tokens after receiving a 401 response, ensuring refreshes are truly necessary:

public function publishWithFreshToken(PostPlatform $postPlatform): array
{
    try {
        return $this->publisher()->publish($postPlatform);
    } catch (TokenExpiredException) {
        $this->refreshToken($postPlatform->socialAccount);
        return $this->publisher()->publish($postPlatform);
    }
}

Second, serialize token refreshes using a cache lock to ensure only one job handles the rotation at a time:

public function refreshToken(SocialAccount $account): void
{
    $lock = Cache::lock("token-refresh:{$account->id}", 30);

    if (!$lock->get()) {
        $account->refresh();
        return;
    }

    try {
        match ($account->platform) {
            Platform::LinkedIn => $this->refreshLinkedIn($account),
            Platform::X => $this->refreshX($account),
            // Additional cases omitted for brevity
        };
    } finally {
        $lock->release();
    }
}

This prevents race conditions and ensures tokens are refreshed efficiently without disrupting scheduled posts.

Reliable Scheduling with Atomic Status Claims

The scheduler itself is straightforward—a console command runs every minute to find due posts and dispatch jobs. The key innovation lies in guaranteeing each post publishes exactly once, even if multiple workers attempt to process it simultaneously.

This is achieved through an atomic status update that doubles as a lock. Only the job that successfully flips a post’s status from Scheduled to Publishing proceeds to dispatch the publish task:

public function handle(): void
{
    Post::query()->due()->each(function (Post $post) {
        $claimed = Post::whereKey($post->id)
            ->where('status', Status::Scheduled)
            ->update(['status' => Status::Publishing]);

        if ($claimed === 1) {
            PublishPost::dispatch($post);
        }
    });
}

This approach eliminates the need for distributed locks or external infrastructure, relying solely on a single conditional database update. From there, jobs are processed by Laravel Horizon, ensuring reliable queue management and retries.

With its Laravel 13 and Vue 3 stack, TryPost offers a familiar environment for developers already comfortable with the framework. By centralizing platform logic, securing token handling, and ensuring atomic scheduling, it provides a robust foundation for managing social media content on your own terms.

AI summary

Buffer ve Hootsuite alternatifi olan açık kaynaklı bir sosyal medya planlayıcıyı Laravel ile nasıl geliştirebileceğinizi öğrenin. OAuth, token yönetimi ve platform entegrasyonları hakkında detaylı rehber.

Comments

00
LEAVE A COMMENT
ID #RAJSGQ

0 / 1200 CHARACTERS

Human check

9 + 4 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.