Quick Social documentation
Quick Social is a self-hosted Laravel application for publishing to your social channels from one admin panel: compose once, preview each post, publish now or schedule it, and follow the results. This guide covers installation, every screen and its controls, and how to connect each channel.
Requirements
| PHP | 8.2 or newer with the extensions BCMath, cURL, Exif, Fileinfo, GD, Gettext, Mbstring, MySQLi, PDO, PDO MySQL and Zip. The installer checks every one of them. |
|---|---|
| Database | MySQL 5.7+ or MariaDB 10.3+. SQLite works for local development. |
| Web server | Apache with mod_rewrite (the included .htaccess files handle the rewriting) or Nginx pointed at public/. |
| HTTPS | Required on a live server. The social platforms only accept https callback URLs for OAuth sign-in, and TikTok refuses plain http entirely, so the root .htaccess sends http requests to https. localhost is exempt, so a local copy runs over plain http. On Nginx, add the equivalent redirect to the server block. |
| FFmpeg | Optional. Needed by the video studio and for cover frames. Installed on the server and on the PATH, or set FFMPEG_PATH in .env. |
| Cron | One entry that runs the Laravel scheduler every minute (see Scheduler). It publishes scheduled campaigns, works the queue that sends every campaign, reads the channels at night and cleans up. Without it nothing is published on schedule and the dashboard shows the scheduler as not running. Hosting without cron can use the web address shown on the Scheduler page from an external cron service. |
Installation with the installer
- Upload the contents of the
quick-socialfolder to your hosting. On cPanel-style hosting upload everything into a folder and point the domain (or subdomain) at that folder; the root.htaccesssends every request topublic/. If you can choose the document root, point it atpublic/directly. - Create an empty MySQL database and a user with full rights on it (cPanel: MySQL Databases).
- Open the site in a browser. Until the application is installed every visit goes to the installer at
/installer/. The application owns its domain or subdomain: the installer and the panel live at the root of that address, not in a sub-folder. - Server requirements: every row must show Enabled. Missing extensions are enabled from the hosting control panel (Select PHP Version / PHP Extensions).
- Folder permissions:
bootstrap/cache,storageand itsapp,frameworkandlogsfolders,resourcesanddatabaseneed permission 0755 or more, and the application root must be writable so the installer can create.env. On Linux:chmod -R 755 storage bootstrap/cache resources database. - Database and admin: the application URL and name, the database name, user, password and host, and your administrator first name, last name, email and password. Every table in that database is replaced by the application's tables. Click Install.
- The installer creates the tables, your first company (named after the application) and your account, writes
.env, links the storage folder and sends you to the login page. The installer locks itself oncestorage/installedexists.
php artisan db:seed: it adds sample companies, campaigns, posts, channel numbers and ideas, and can be run again to restore them.Manual installation (developers)
composer install
cp .env.example .env # fill in the database settings
php artisan key:generate
php artisan app:install # database, storage link, the administrator account (add --samples for the preview content)
npm install && npm run build
php artisan serve
app:install asks for the administrator's name, email and password (or takes --name, --email and --password; add --samples for the sample content) and marks the application installed, so the browser installer never shows. Open /admin/login and sign in with that email and password. The email can be changed under Profile.
Scheduler (cron)
Scheduled campaigns, the nightly read of the channels for Feeds and Analytics, and the clean-up of temporary media all run from the Laravel scheduler. Add one cron entry on the server:
* * * * * /usr/bin/php /home/USER/quick-social/artisan schedule:run >> /dev/null 2>&1
Settings, Scheduler shows this line with the server's own paths and a Copy button, whether the scheduler has run in the last five minutes, whether the queue worker has been seen, and the hour of the two nightly jobs (the channel read and the temporary media clean-up). The dashboard also shows the scheduler's state. Locally, php artisan schedule:work does the same job. The times of the nightly jobs are server time.
The queue
Every campaign is sent by a queued job, from the composer, the calendar, the dashboard and the scheduler alike, so a long video upload never runs inside a web request. With QUEUE_CONNECTION=database (the default) the cron line above also works the queue for most of every minute; a server that can keep a process running may run php artisan queue:work as a service instead, and after an update run php artisan queue:restart. With QUEUE_CONNECTION=sync there is no worker at all: a campaign is sent inside the request or the scheduler tick that started it.
A channel that fails for a passing reason (an outage, a rate limit) is tried again after 5, 15 and 45 minutes; a channel that refuses the sign-in is marked so on the company's page and in the campaign log. A run the server interrupted is closed after 45 minutes with what was recorded; nothing is sent twice.
Hosting without cron
Settings, Scheduler also shows a web address. An external cron service that opens it every minute runs the same tick the cron line would. The address carries a secret made for this installation; treat it like a password.
Backups
Back up the database, the storage/app/public folder (uploads, logos and generated media) and the .env file with your hosting's backup tool. The .env file holds the key that every saved token and API key is encrypted with: without it a restored database cannot read them, so never run php artisan key:generate on an installed site.
First login
Sign in at /admin/login with the administrator email and password you entered in the installer. The dashboard opens with a checklist: connect a channel, add an AI key, set your time zone and name your brand. The checklist disappears on its own once every step is done, or use Put away.
Forgot the password? Forgot password? on the login page emails a reset link once SMTP is set up. Without email, run php artisan account:password on the server to set a new one.
The sidebar
The sidebar follows the order the work happens. Dashboard sits on top. Publish holds Social campaigns (Create campaign, All campaigns, Campaign log), Publish video (Create video, All videos, Video log), the Calendar and Ideas. Measure holds Feeds and Analytics (Overview, Campaign analytics, Video analytics). Create holds the Media library and the Studio (Image studio, Video studio). Settings closes the list. A group opens on click and remembers its state; the sidebar collapses to icons with the button in the top bar, and a collapsed group shows its pages on hover.
Three pages belong to every campaign and video: the composer where it is made, the archive where it is kept, edited or deleted, and the log where each publish run is recorded. Their numbers live under Analytics.
Dashboard
Compose
The quick composer at the top: pick a format (Auto, Link post, Image post, Video post, Publish video), type the message or attach media with Image and Video, and click Compose. Auto asks the AI to plan the post for the channels you have connected; the result opens in the full composer.
Needs attention
Failed or partly failed runs (with Retry), channels that need a new sign-in (Sign in), drafts that are not scheduled (Open), and the scheduler status.
Channels
One tile per connected channel, in its colour: the account, its followers with the change over the week (its reach where the channel reports no followers), the posts, reach and engagements of the last seven days, and a line of the engagements day by day. The row scrolls sideways. A channel that only publishes (a LinkedIn profile, Telegram, WhatsApp, Discord) shows what is stored about its posts.
Last 7 days
New posts, reach, engagements, engagement rate and followers, read from the channels. Read the channels now fetches fresh numbers.
Ideas for the week
Five AI-written post ideas for the coming days. Compose opens one in the composer, Save keeps it in Ideas, Dismiss hides it, Suggest again asks for a new set.
This week and Best times
The week's scheduled campaigns with links to the calendar, and a heat map of the best hours to post per channel, from the channel's own numbers.
Social campaigns: Create campaign
Social campaigns holds three pages: Create campaign (the composer), All campaigns (the archive) and the Campaign log (the record of publish runs).
The composer publishes link posts, image posts and video posts to the social channels.
| Control | What it does |
|---|---|
| Format tabs | Link post, Image post, Post a video. Each format lists only the channels that accept it. |
| Channel chips | Click to select a channel. Grey chips are channels that are not connected yet; hover them for the reason. |
| Message | The text of the post; the first link in it is the post's link, shown as the channel shows a shared link. Media opens the media library, Emoji inserts an emoji, Write with AI drafts the text from a short brief. |
| Preview | One card per channel, in that channel's look, with the character counter where the platform enforces one. Each card has its own Publish button. |
| Save draft | Keeps the campaign without sending it. Drafts open again from the calendar and the dashboard. |
| Schedule | Pick a date and time; the scheduler publishes it. The campaign appears on the calendar. |
| Publish all | Shows the selected channels as they stand, a check for each one that is ready and what the others still need; Publish now sends the open format to every one of them, Back returns to the composer. The results appear under the composer with the post links or the error per channel. |
Channel-specific options appear when their channel is selected: subreddit and title for Reddit, the WhatsApp template.
Channels, the row at the top of the dashboard, carries one tile per signed-in channel: its followers with the week's change, its posts, reach and engagements over the last seven days, and a line of its daily engagements. The row scrolls sideways.
Opportunities lists the channels a recent campaign did not go to although they are signed in and take its format, each drawn as that channel would show the post: a row on the dashboard, and the full list under Social campaigns, Opportunities (/admin/opportunities), by channel, twenty at a time with Load more. On each card, Publish on … sends the campaign to that channel at once and records it on the campaign; Edit opens the composer with the campaign's content and that channel picked; the cross dismisses the card for good. Refresh reads the list again.
Social campaigns: All campaigns
The archive: every campaign, newest first, with its type, the channels it went (or will go) to, its status and date. Filter by Published, Planned (drafts, scheduled and missed) or Failed, or search by title. Edit opens a planned campaign in the composer and a sent one on its record page. The bin removes a campaign together with its runs (a campaign being published right now waits until it finishes). All videos under Publish video is the same archive for video uploads.
The record page
A sent campaign's page holds everything it carried: the Shared message (or a video's title, description and tags), the media, and one card per channel drawn the way that channel shows the post, as in the composer. Edit the shared fields and press Update all channels, or press Edit on a card to open that channel's own text (or title, description and tags) and settings inside it, then its own Update; the change is saved on the record and sent to that channel alone. Use shared text puts the shared fields back. Each card says what its channel still lets change after publishing: the text on Facebook, Telegram, Discord and Reddit (text posts); title, description, link and board on Pinterest; title, description, tags, thumbnail and settings on YouTube; title, description, thumbnail and privacy on Vimeo. TikTok, Instagram, X, LinkedIn, Threads, Bluesky and WhatsApp keep what they were sent, so their cards carry no Update. Write with AI under a field drafts it for the channels of the record, or for one channel alone on its card. On a video, the Cover strip under the player takes a new thumbnail from this computer, the library or Google Drive; it is sent to YouTube and Vimeo with the next Update, once each.
Social campaigns: Campaign log
Every publish run of a social campaign, newest first, with the channels it went to, how many were sent and how many failed. Filter by status, search by title. Video uploads have their own Video log under Publish video. Open a run to see each channel's result: the post ID and link for successes, the error text for failures, and Retry to send a failed channel again (the retry is recorded as a new run). The activity log lists what happened step by step.
Publish video: Create video, All videos, Video log
Create video is the native video composer; All videos is the archive of uploads, each opening on its record page (see All campaigns); the Video log is the record of upload runs. Native video uploads with each platform's own settings: YouTube (visibility, schedule, category, language, playlist, made for kids, notify subscribers, first comment, Short or video), Vimeo (privacy), TikTok (who can view, comments, duet, stitch), Instagram Reels (also show on the profile feed), Facebook Reels and Pinterest video pins (board, destination link).
Add the video by dropping a file, choosing one from the library or pasting a hosted URL; add an optional cover image or pick the frame time used as the cover. Generate a video with AI creates a short clip from a description and puts it in the library.
Calendar
Week and month views of scheduled, published and missed campaigns, plus the drafts list. Drag a scheduled campaign to another day to reschedule it. Click a campaign for its actions: Edit (opens it in the composer), Publish now, Back to draft, Duplicate, Delete. The connected channels are shown in the strip at the top.
Ideas
Every idea you saved from the dashboard, with the day it was suggested for and why. Compose opens it in the dashboard composer, Remove moves it to the Removed list, from where Restore brings it back and Delete removes it for good. The lightbulb in the top bar opens the same lists as a drawer on any page.
Feeds
The posts on your channels as the channels report them, all together or one channel at a time, with their numbers. Reuse opens a post's text and media in the composer. Some channels are read on demand to respect their API budgets; the button on the channel's card reads it.
Analytics: Overview
Reach, engagements, followers and posts over the last 7, 30 or 90 days, per channel and in total, with the best times heat map. Read the channels now fetches fresh numbers; the scheduler reads them every night.
Analytics: Campaign and Video analytics
Campaign analytics lists every campaign that went out with the audience and engagement it has gathered so far and its engagement rate; Video analytics does the same for video uploads. Open one for its page.
A campaign's page is its scorecard. The band at the top shows the channels with their outcome, when it went out and when the channels were last read, and the two figures that matter: the audience (impressions, views or reach, whichever the channel gives) and the engagements (likes, comments, shares, saves and clicks), each with its trend and what the last read added. Growth since it went out draws the audience day by day with the engagement each nightly read added; By channel shows each channel's share; below, one card per channel shows the post it made, the numbers that channel reports and a link to the post. A failed channel shows the reason with Retry, or Sign in when the channel needs it. Publish again opens a fresh draft with the same content. Channels that do not report numbers (Telegram, WhatsApp, Discord, a LinkedIn member profile) say so on their card.
Media library
Everything uploaded or generated. Add media uploads files (or drop them anywhere on the page); filter by images or videos, search by name. A file's side panel shows its size and links to use it in the composer, the publisher or the studios, and Delete removes it. The cap per file comes from the server's PHP limits; an optional total cap is set with MEDIA_LIBRARY_LIMIT_MB.
Image and video studio
Image studio: pick a size (post, story, cover, thumbnail), start from a library image or an AI-generated one, add text layers with fonts, colours and effects, and save the result to the library.
Video studio: open a library video, trim it, add captions and a cover frame, and render it on the server with FFmpeg. The render lands in the library, ready to publish.
Companies
The panel can publish for more than one company (a brand, a client, a project). Each company has its own social channels, campaigns, calendar, campaign log, ideas, feeds and analytics. AI providers, SMTP, the media library and the panel's branding are shared by all of them.
The company switcher
The top bar shows the company you are working in. Click it to switch: every page then shows that company's channels and campaigns. The choice is remembered. Add company and Manage companies sit at the bottom of the list.
Managing companies
Settings, Companies (/admin/settings/companies) lists every company with its channel and campaign counts. Click a card to open the company: its name, logo, contact details (website, email, phone and address, all optional) and brand voice (the description the AI writer, the planner and the ideas of the week write from, and Tailor text per channel with AI: with it on, the composer writes each selected channel its own version of the message, shown in its preview card and editable there) on the left, and its social channels on the right. Opening a company makes it the current one. Remove deletes a company with all of its channels, campaigns and reports after a confirmation; the last company cannot be removed.
The scheduler publishes every company's campaigns, each with that company's own channels, and the nightly channel read covers every company.
Settings
/admin/settings shows one card per area: Companies, AI providers, SMTP, Scheduler, Branding and Notifications. Social channels live on each company's page (/admin/settings/companies/{id}/edit); AI settings (/admin/settings/ai) and SMTP settings (/admin/settings/smtp) are shared by every company. Save settings in the page header saves the open page. Values are encrypted before they are stored; a saved secret is never shown again, paste a new value to replace it.
Social channels
On the right of a company's page. One card per channel with its status, the account it publishes as, and the buttons next to the title: Sign in with … for channels that connect through OAuth, Disconnect once connected. Keys opens the credentials of the channel (client IDs, secrets, tokens) and shows the Redirect URI to register in the platform's developer app. Every company keeps its own keys and sign-ins. See Connecting each channel.
AI providers
A key per provider (OpenAI, Anthropic, Google Gemini, OpenRouter). A pasted key is checked with the provider straight away. Under AI features, choose the provider and model for text, image generation, image editing and video generation; the model lists come from the provider. The brand voice the AI writes with is set per company, see Companies.
SMTP
The mailbox that sends password reset emails: host, port, encryption, username, password and the from address. Send a test email sends one to your account.
Profile, branding, notifications
From the account menu at the bottom of the sidebar:
Profile: name, email, avatar, time zone (used for scheduling and the calendar) and password.
Branding: the name, logo, favicon, colours, fonts, footer text and light/dark theme of the panel. The brand voice used by the AI belongs to each company.
Notifications: everything the app tells you about (runs, sign-ins that expired, channels connected), with per-event switches and browser notifications. The bell in the top bar shows the unread ones.
Connecting each channel
Every channel is connected under Settings, Channels (the company's channel cards). Open a card's Keys to paste what the platform gives you, then press the card's Sign in button where there is one. Channels that use OAuth need an app in the platform's developer portal, and that app must carry this redirect URI exactly (it is also shown under the card's Keys, with your own domain filled in):
https://your-domain.com/admin/settings/connect/{provider}/callback
where {provider} is facebook, twitter, linkedin, tiktok, youtube, pinterest, reddit, threads or vimeo. The platforms only accept https redirect URIs, so the application must be online with a valid certificate before a channel can be signed in. The steps below are what each developer portal asks for; the portals change their wording now and then, but the pieces stay the same.
Facebook Page and Instagram
- Go to developers.facebook.com/apps and press Create app. Choose the Business type (or "Other" then "Business"), name it after your brand, and pick the Business portfolio that owns your Page if you have one.
- In the app's dashboard add the Facebook Login for Business product (plain Facebook Login also works). Under its Settings, paste the redirect URI for
facebookinto Valid OAuth Redirect URIs and save. - Open App settings, Basic. Copy the App ID and the App secret (press Show) into the Facebook card's Keys as App ID and App secret, and save.
- Press Sign in with Facebook on the card. Facebook asks which Pages the app may manage; allow the Page you post to. The application asks for the permissions
pages_show_list,pages_manage_posts,pages_read_engagement,pages_read_user_content,read_insightsandbusiness_management. - Pick the Page from the list. The application stores a permanent Page token and the Page ID itself; if the Page has a professional Instagram account linked to it, the Instagram card connects at the same time.
- While the app is in Development mode only people with a role in the app (Roles, under App settings) can sign in, which is fine for your own Pages. To let other people connect their Pages, submit the same permissions for App review and switch the app to Live.
Prefer a pasted token? Generate a long-lived Page access token in the Graph API Explorer (choose your app, your Page and the same permissions), then paste it with the Page ID into the card instead of signing in. Instagram then needs the Instagram account ID (from the Page's Instagram settings, or the Graph API field instagram_business_account).
X (Twitter)
- Sign in at developer.x.com and open the Developer Portal. On a first visit, choose a plan (Free covers posting from your own account) and create a Project, then an App inside it.
- Open the app's Settings and press Set up under User authentication settings. Choose Read and write for the permissions, Web App, Automated App or Bot for the type, paste the redirect URI for
twitteras the Callback URI, put your site's address as the Website URL and save. - Open Keys and tokens. Under OAuth 2.0 Client ID and Client Secret copy both into the X card's Keys as OAuth 2.0 Client ID and Client Secret, and save.
- Press Sign in with X and allow the access. The application asks for
tweet.read,tweet.write,users.read,media.writeandoffline.access, and renews the token itself from then on.
- Go to linkedin.com/developers/apps and press Create app. Give it a name, a LinkedIn Page it belongs to (every app needs one; create a Page first if you have none), a logo and the legal agreement.
- On the app's Products tab request Share on LinkedIn and Sign In with LinkedIn using OpenID Connect. Both are granted at once. To post as a company page and read its statistics, also request the Community Management API; LinkedIn reviews that one and asks what the app does.
- On the Auth tab paste the redirect URI for
linkedinunder Authorized redirect URLs for your app. Copy the Client ID and the Primary Client Secret into the LinkedIn card's Keys, and save. - Press Sign in with LinkedIn and allow the access. The application asks for
openid,profileandw_member_social, and forw_organization_socialandr_organization_adminas well once the Community Management API is on the app. After signing in, pick Post as: your profile or one of the pages you administer. Posting to a page also lets Feeds and Analytics read it.
TikTok
- Sign in at developers.tiktok.com, open Manage apps and press Connect an app. Fill in the name, category and description, and add your site's Terms of Service and Privacy Policy addresses, which TikTok requires.
- Under Add products add Login Kit and Content Posting API. In Login Kit paste the redirect URI for
tiktok; in Content Posting API turn on Direct Post. - Under Scopes add
user.info.basic,user.info.stats,video.upload,video.publishandvideo.list, then submit the app for review; TikTok asks for a short screen recording of the sign-in and the posting. - Copy the Client key and Client secret from the app's credentials into the TikTok card's Keys, save, and press Sign in with TikTok.
YouTube
- Open console.cloud.google.com and create a project (or pick one). Under APIs & Services, Library enable YouTube Data API v3 and YouTube Analytics API.
- Under APIs & Services, OAuth consent screen (Google Auth Platform) set the app name, the support email and the developer email, choose External, and add your Google account under Test users. In testing, only test users can sign in, which is fine for your own channel; publishing the app to production needs Google's verification for the YouTube scopes.
- Under Credentials press Create credentials, OAuth client ID, type Web application. Add the redirect URI for
youtubeunder Authorized redirect URIs. - Copy the Client ID and Client secret into the YouTube card's Keys and save.
- Press Sign in with Google on the YouTube card and allow the access; the application asks for
youtube.upload,youtube.force-ssl,youtube.readonlyandyt-analytics.readonly.
- Convert the account to a business account if it is not one (Settings, Account management on pinterest.com). Then open developers.pinterest.com/apps and press Connect app; describe what the app does and accept the developer terms.
- In the app's configuration add the redirect URI for
pinterestunder Redirect URIs. Copy the App ID and the App secret into the Pinterest card's Keys and save. - New apps start in trial access, which allows posting to your own account; request standard access from the same page when other people's accounts need to connect.
- Press Sign in with Pinterest and allow the access (
boards:read,pins:read,pins:write,user_accounts:read). Enter the Default board ID pins land on (the number in the board's address on pinterest.com, or leave it empty and pick the board in the composer, which lists your boards once you are signed in).
Telegram
- In Telegram open a chat with @BotFather, send
/newbot, and answer with a display name and a username ending inbot. BotFather replies with the bot token; paste it into the Telegram card's Keys. - Open your channel (or group), go to Administrators and add the bot as an administrator with the right to post messages.
- Enter the Channel / chat ID: for a public channel its handle, such as
@yourchannel; for a private channel or group its numeric ID, such as-1001234567890(forward a message from it to @userinfobot or @getidsbot to read the ID). Save; the application checks the bot and the channel as it saves.
- Signed in as the account that posts, open reddit.com/prefs/apps and press create another app at the bottom.
- Choose web app, give it a name and a description, and paste the redirect URI for
redditas the redirect uri. Press create app. - The Client ID is the short string under the app's name (below "web app"); the secret is shown next to it. Copy both into the Reddit card's Keys, save, and press Sign in with Reddit (
identity,submit,read,mysubreddits,history). - Set the Default subreddit; the composer lets you choose another per post. The account must be allowed to post in it.
WhatsApp Business
- In a Meta app (the one from the Facebook steps works) add the WhatsApp product. Its API Setup page shows a test number to start with; to send from your own number, add it under Phone numbers and verify it (the number must not be registered in the WhatsApp app on a phone).
- On the same page copy the Phone number ID and the WhatsApp Business Account ID into the WhatsApp card's Keys.
- The temporary token on that page expires within a day. For a lasting token open Business settings, System users, add a system user (Admin), assign it the WhatsApp app and the WhatsApp account, and Generate new token with the permissions
whatsapp_business_messagingandwhatsapp_business_management, expiry Never. Paste it as the Access token. - Enter the Recipients: the phone numbers the campaign is sent to, one per line in international format. Save; the application checks the token and the number as it saves.
Threads
- Go to developers.facebook.com/apps and create an app; when asked what the app should do choose Access the Threads API (Threads apps are separate from Facebook apps).
- Under Use cases, Access the Threads API press Customize and add the permissions
threads_basic,threads_content_publishandthreads_manage_insights. Under Settings paste the redirect URI forthreadsunder Redirect Callback URLs and add your site under Uninstall and Delete callback URLs (any page of your site is accepted). - Open App settings, Basic and copy the Threads App ID and Threads App Secret (they differ from the Facebook ones) into the Threads card's Keys, and save.
- Under Roles, Threads testers invite the Threads account that posts, and accept the invitation in the Threads app (Settings, Account, Website permissions). Press Sign in with Threads and allow the access.
Bluesky
- In Bluesky open Settings, Privacy and security, App passwords and press Add app password. Name it after this application and copy the password shown once.
- Enter the Handle (such as
yourname.bsky.social, or your own domain if the account uses one) and the App password in the Bluesky card's Keys. Save; the application signs in as it saves to check them. Never use the account's main password here.
Discord
- In your Discord server open the channel's settings (the cog next to the channel name), go to Integrations, Webhooks and press New Webhook. Give it a name and an avatar; they show as the author of every post.
- Press Copy Webhook URL and paste it as the Webhook URL in the Discord card's Keys. Save; the application checks the webhook as it saves.
Vimeo
- Go to developer.vimeo.com/apps and press Create an app. Name it, describe it, and paste your site's address as the app URL.
- In the app, under Authentication, paste the redirect URI for
vimeounder Your callback URLs. Copy the Client identifier and the Client secret into the Vimeo card's Keys, and save. - Under Permissions request Upload access; Vimeo reviews it (usually within a few days) and uploads fail until it is granted. Then press Sign in with Vimeo (
public,private,upload,edit).
Checklist
| Channel | What goes in the card | Sign-in button | Portal |
|---|---|---|---|
| App ID, App secret (or a pasted Page token and Page ID) | Sign in with Facebook, then pick the Page | developers.facebook.com | |
| Nothing when the Page is connected; else an access token and the Instagram account ID | — | Linked to the Facebook Page | |
| X (Twitter) | OAuth 2.0 Client ID, Client Secret | Sign in with X | developer.x.com |
| Client ID, Primary Client Secret | Sign in with LinkedIn, then Post as | linkedin.com/developers | |
| TikTok | Client key, Client secret | Sign in with TikTok | developers.tiktok.com |
| YouTube | Client ID, Client secret | Sign in with Google | console.cloud.google.com |
| App ID, App secret, Default board | Sign in with Pinterest | developers.pinterest.com | |
| Telegram | Bot token, Channel / chat ID | — | @BotFather |
| Client ID, Client secret, Default subreddit | Sign in with Reddit | reddit.com/prefs/apps | |
| WhatsApp Business | Access token, Phone number ID, Business Account ID, Recipients | — | Meta app, WhatsApp product |
| Threads | Threads App ID, Threads App Secret | Sign in with Threads | developers.facebook.com (Threads use case) |
| Bluesky | Handle, App password | — | Bluesky settings, App passwords |
| Discord | Webhook URL | — | Channel settings, Integrations |
| Vimeo | Client identifier, Client secret | Sign in with Vimeo | developer.vimeo.com |
A channel whose token expires or is revoked shows Sign in again on its card and on the dashboard, and the scheduler stops sending to it until you do. The hourly channel check keeps this current.
AI providers
Keys are optional per provider. A feature runs on the provider chosen for it under AI features; if that provider has no key, the feature explains what is missing when you use it. Image editing needs a provider that supports it (OpenAI, Gemini or OpenRouter with a capable model); video generation needs Gemini (Veo) or OpenAI (Sora).
SMTP
Password reset emails need a mailbox. Enter the SMTP details under Settings, SMTP, and send a test email. Without SMTP, set a new password from the server with php artisan account:password.
Firebase push notifications
With Firebase Cloud Messaging set up under Settings, Firebase, every notification (a campaign published or failed, a channel that needs a sign-in, AI media that is ready) also reaches the browser the moment it happens: the bell updates at once, a system notification shows even when the panel is in another tab or closed, and a page that is following a publish run refreshes right away. The application must run over https for the browser to allow this.
- At console.firebase.google.com create a project (or open one) and add a Web app to it (the
</>icon on the project overview). - The console shows the app's
firebaseConfig: Project settings, General, Your apps. Copy each value into the Firebase Cloud Messaging fields, or press Upload config file with a JSON file of them. - Under Project settings, Cloud Messaging, Web configuration press Generate key pair and copy the key into Web Push certificate (VAPID key).
- Under Project settings, Service accounts press Generate new private key. Press Upload config file under Firebase Admin SDK and pick the downloaded file; the fields fill in.
- Save. The browser asks to allow notifications on the next page; allow them, then press Send a test to see one arrive. Each account allows notifications once per browser; the toggle under Notifications does the same.
Both files are kept in storage/app/firebase; the web app config is served to the page and to firebase-messaging-sw.js, the service account never leaves the server. Every push and every failure is written to notification_logs.
Google Drive
Each company has its own Drive, signed in on the company's page under Brand voice. With a Drive signed in, the Media library and every media strip in the composer carry a Google Drive tile: pick pictures and videos from the Drive and they come into the library, ready to post. A library file's Save to Google Drive puts it in a Quick Social folder in that Drive. One Drive serves the whole panel.
- In the Google Cloud project used for YouTube (or a new one) enable the Google Drive API under APIs & Services, Library.
- Create an OAuth client of type Web application (or reuse the YouTube one) and add the redirect URI shown on the company's page.
- Paste the Client ID and Client secret and press Sign in with Google. The application asks for
drive.readonly(to list and import) anddrive.file(to save).
Demo mode
Set APP_ENV=demo in .env to show the application without letting visitors change anything: every save, publish and delete answers with a demo notice while logging in still works. Nothing reaches the channels either: no post is sent, no feed or number is read, no sign-in is checked or renewed, and scheduled campaigns are not sent; the pages show what is stored. Use it for a public preview.
Updating
- Back up the database and the
storage/folder. - Upload the new files over the old ones, keeping your
.env,storage/andpublic/storage. - Run
php artisan migrate --forceandphp artisan optimize:clear.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| The installer says a folder is not writable | Set permissions: chmod -R 775 storage bootstrap/cache, and make sure the web server user owns the application folder. |
| Uploaded images do not show | The storage link is missing. Run php artisan storage:link, or create public/storage as a link to storage/app/public. |
| Scheduled campaigns stay scheduled | The cron entry is missing or not running. Add schedule:run every minute; the dashboard shows when it last ran. |
| A channel says "Sign in again" | Its token expired or was revoked. Open Settings and sign in to the channel again. |
| OAuth sign-in fails with a redirect error | The redirect URI in the platform's app does not match the one shown under Keys. Copy it exactly, including https. |
| Instagram or TikTok refuse a local file | Those platforms download media from a public URL. The application must be reachable online with a public APP_URL. |
| Video studio cannot render | FFmpeg is not installed or not found. Install it on the server or set FFMPEG_PATH. |
| 500 error after moving servers | Run php artisan optimize:clear and check that .env has the right database details. |
Changelog
1.0.0: first release.