How to Build an AI Social Media Post Scheduler Using Gemini and Late API in Next.js

by SkillAiNest

Social media has become an important tool for people and businesses to share ideas, promote products and connect with their target audience. But creating regular posts and managing schedules across multiple platforms can be time-consuming and repetitive.

In this tutorial, you’ll learn how to create an AI-powered social media post scheduler Geminifor , for , for , . Late APIand Next dot j.

We will use the Gemini API to generate engaging social media content from next.js, user prompts to publish and schedule posts across multiple social media platforms from a single platform.

Social media platform

Table of Contents

Conditions

To fully understand this tutorial, you need a basic understanding of React or Next.js.

We will use the following tools:

  • Late API: A social media API that lets you create and schedule posts across 13 social media platforms from a single dashboard.

  • Next dot j: A reactive framework for building fast, scalable web applications, handling both front-end and back-end.

  • Google Gemini API: Provides access to Google’s AI model to generate text and other content based on user gestures.

Setup and Installation

Create a new Next.js project using the following code snippet:

npx create-next-app post-scheduler

Install project dependencies. We will use day J Working with JavaScript dates makes it easy to schedule and publish social media posts at the right time.

npm install @google/genai dayjs utc

Next, add a .env.local File containing your Gemini API key in the root of your next.js project:

GEMINI_API_KEY=

Once everything is compiled, your next .js project is ready. Now, start building! 🚀

Late API and available social media platforms

How to schedule late social media posts

of late is a social media scheduling platform that allows you to integrate your social media accounts and publish posts across multiple platforms. In this section, you’ll learn how to create and schedule social media posts using the Late Dashboard.

To begin, create a Late account And sign in.

Sign in and get a late API key

Create an API key and add it .env.local file in your next .js project.

LATE_API_KEY=

Copy the late API key

Integrate your social media accounts later so you can manage and publish posts across platforms.

Social media platform

After connecting your social media accounts through OAUTH, you can start writing, posting, and scheduling content directly on your social media platforms.

A Twitter (x) account is attached

Late lets you write your own post content and attach media files directly to the dashboard.

Create social media content from your dashboard

You can choose when your content should be published: post immediately, schedule for later, add it to a job queue, or save it as a draft.

Publish your post

Once a post is published, you can view its status and view it directly in the dashboard using the post link.

A late social media post was prepared

🎉 Congratulations! You have successfully created your first post using Late Dashboard. In the next sections, you will learn how to use Late API To create and schedule posts directly from your applications.

How to Create a Next.js App Interface

In this section, you will create the user interface for the application. The app used a page path with conditional rendering to display recent posts, an AI prompt input field, and a form that allowed users to create or schedule posts.

App Review

Before we proceed, create a types.d.ts file inside your Next.js project and copy the following code snippet into the file:

interface Post {
    _id: string;
    content: string;
    scheduledFor: string;
    status: string;
}

interface AIFormProps {
    handleGeneratePost: (e: React.FormEvent) => void;
    useAI: boolean;
    setUseAI: React.Dispatchboolean>>;
    prompt: string;
    setPrompt: React.Dispatchstring>>;
    disableBtn: boolean;
}

interface FormProps {
    handlePostSubmit: (e: React.FormEvent) => void;
    content: string;
    setContent: React.Dispatchstring>>;
    date: string;
    setDate: React.Dispatchstring>>;
    disableBtn: boolean;
    setUseAI: React.Dispatchboolean>>;
    useAI: boolean;
}

types.d.ts The file defines all data structure and type declarations used throughout the application.

Copy the following code snippet app/page.tsx file:

"use client";
import Nav from "./components/Nav";
import { useState } from "react";
import NewPost from "./components/NewPost";
import PostsQueue from "./components/PostsQueue";

export default function Page() {
    const (showPostQueue, setShowPostQueue) = useState<boolean>(false);
    return (
        
'w-full h-screen'>
); }

Page Presents the component Nav The component uses conditional rendering to display either PostsQueue or NewPost component based on component value showPostQueue State

a components Folder to store page components used in the application.

cd app
mkdir components && cd components
touch Nav.tsx NewPost.tsx PostElement.tsx PostsQueue.tsx

Add the code snippet below Nav.tsx file:

export default function Nav({
    showPostQueue,
    setShowPostQueue,
}: {
    showPostQueue: boolean;
    setShowPostQueue: React.Dispatchboolean>>;
}) {
    return (
        
    );
}

Copy the following code snippet PostsQueue.tsx file:

"use client";
import { useEffect, useState, useCallback } from "react";
import PostElement from "./PostElement";

export default function PostsQueue() {
    const (posts, setPosts) = useState(());
    const (loading, setLoading) = useState<boolean>(true);

    return (
        
'p-4'>

'text-xl font-bold'>Scheduled Posts

{loading ? (

'text-sm'>Loading scheduled posts...

) : (
'mt-4'> {posts.length > 0 ? ( posts.map((post) => ) ) : (

No scheduled posts available.

)}
)}
); }

PostsQueue.tsx The component displays a list of previously created posts along with their current status, indicating whether each post has been published or scheduled for later. When the data is being loaded, it displays a loading message, and once loaded, it renders each post using PostElement Ingredients

Add the following PostElement.tsx Ingredients:

export default function PostElement({ post }: { post: Post }) {
    export const formatReadableTime = (isoString: string) => {
        const date = new Date(isoString); 
        return date.toLocaleString(undefined, {
            year: "numeric",
            month: "short",
            day: "numeric",
            hour: "2-digit",
            minute: "2-digit",
            second: "2-digit",
            hour12: true, 
        });
    };

    return (
        
'p-4 border flex items-center justify-between space-x-4 rounded mb-2 hover:bg-gray-100 cursor-pointer'>

'font-semibold text-sm'>{post.content.slice(0, 100)}

'text-blue-400 text-xs'> Scheduled for: {formatReadableTime(post.scheduledFor)}

'text-sm text-red-500'>{post.status}

); }

Finally, copy the following code snippet NewPost.tsx file:

"use client";
import { useState } from "react";

export default function NewPost() {
 const (disableBtn, setDisableBtn) = useState<boolean>(false);
 const (useAI, setUseAI) = useState<boolean>(false);
 const (content, setContent) = useState<string>("");
 const (prompt, setPrompt) = useState<string>("");
 const (date, setDate) = useState<string>("");

 
 const handleGeneratePost = async (e: React.FormEvent) => {
  e.preventDefault();
  setDisableBtn(true);
 };

 
 const handlePostSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
 };

 return (
  
'w-full p-4 h-(90vh) flex flex-col items-center justify-center border-t'>

'text-xl font-bold'>New Post

{useAI ? ( ) : ( )}
); }

NewPost Renders components conditionally AIPromptForm And PostForm. When the user chooses to generate content using AI, an iperemptorform component appears to collect the prompt. Once the content is ready, the Postform component is displayed, allowing the user to edit, create or schedule a post.

Add the ingredients below NewPost.tsx file:

export const AIPromptForm = ({
    handleGeneratePost,
    useAI,
    setUseAI,
    prompt,
    setPrompt,
    disableBtn,
}: AIFormProps) => {
    return (
        
    );
};


export const PostForm = ({
    handlePostSubmit,
    content,
    setContent,
    date,
    setDate,
    disableBtn,
    setUseAI,
    useAI,
}: FormProps) => {
    const getNowForDatetimeLocal = () => {
        const now = new Date();
        return new Date(now.getTime() - now.getTimezoneOffset() * 60000)
            .toISOString()
            .slice(0, 16);
    };

    return (
        
    );
};

Congratulations! You have completed the application interface.

How to integrate the Gemini API for PostGeneration

Here, you’ll learn how to generate post content with user prompts using the Gemini API.

Before we proceed, make sure you have copied your API key from the master Google AI Studio.

Generate a Gemini API key

Make one api Next. js folder inside app Directory This folder will contain the API routes used to generate AI content and create or schedule posts using the Late API.

cd app && mkdir api

Next, create a generate folder within the api directory and add a route.ts file Copy the following code into the file:


import { NextRequest, NextResponse } from "next/server";
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY! });

export async function POST(req: NextRequest) {
    const { prompt } = await req.json();

    try {
        const response = await ai.models.generateContent({
            model: "gemini-3-flash-preview",
            contents: `
    You are a social media post generator, very efficient in generating engaging posts for Twitter (X). Given a topic, generate a creative and engaging post that captures attention and encourages interaction. This posts will always be within the character limit of X (Twitter) which is 280 characters, which includes any hashtags or mentions, spaces, punctuation, and emojis.

    The user will provide a topic or theme, and you will generate a post based on that input.
    Here is the instruction from the user:
    "${prompt}"`,
        });
        if (!response.text) {
            return NextResponse.json(
                {
                    message: "Encountered an error generating the post.",
                    success: false,
                },
                { status: 400 },
            );
        }

        return NextResponse.json(
            { message: response.text, success: true },
            { status: 200 },
        );
    } catch (error) {
        return NextResponse.json(
            { message: "Error generating post.", success: false },
            { status: 500 },
        );
    }
}

api/generate The endpoint accepts user input and generates post content using it Gemini API.

Now you can send the newly created request /api/generate endpoint from NewPost Update components handleGeneratePost function as shown below:

const handleGeneratePost = async (e: React.FormEvent) => {
    e.preventDefault();
    setDisableBtn(true);
    const result = await fetch("/api/generate", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({ prompt }),
    });

    const data = await result.json();
    if (data.success) {
        setUseAI(false);
        setContent(data.message);
        setPrompt("");
    }
    setDisableBtn(false);
};

handleGeneratePost The function accepts a user input and returns the AI ​​infilled content.

How to use the Late API in Next.js

of late The API provides endpoints that let you program, schedule, and manage programs. This allows you to integrate social media posting directly into your applications or automation workflows.

To get started, copy your late API key and account ID of your social media platforms .env.local file:

LATE_API_KEY=
ACCOUNT_ID=


GEMINI_API_KEY=

Connect to the Twitter (X) account and copy the account ID

Note: In this tutorial, we will use Twitter (x) as a social media platform to schedule posts. You can adopt the same workflow with other platforms with late API support by updating the platform and account ID values ​​in your API requests.

Make one api/post An endpoint to accept post content and schedule or publish posts using the Late API.

cd api
mkdir post && cd post
touch route.ts

Next, add the following to the POST method post/route.ts:

import { NextRequest, NextResponse } from "next/server";
import utc from "dayjs/plugin/utc";
import dayjs from "dayjs";

dayjs.extend(utc);

export async function POST(req: NextRequest) {
    const { content, publishAt } = await req.json();

    
    const nowUTC = publishAt ? dayjs(publishAt).utc() : null;
    const publishAtUTC = nowUTC ? nowUTC.format("YYYY-MM-DDTHH:mm") : null;

    try {
        const response = await fetch("https://getlate.dev/api/v1/posts", {
            method: "POST",
            headers: {
                Authorization: `Bearer ${process.env.LATE_API_KEY}`,
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                content,
                platforms: (
                    {
                        platform: "twitter",
                        accountId: process.env.ACCOUNT_ID!,
                    },
                ),
                publishNow: !publishAt,
                scheduledFor: publishAtUTC,
            }),
        });

        const { post, message } = await response.json();

        if (post?._id) {
            return NextResponse.json({ message, success: true }, { status: 201 });
        }

        return NextResponse.json({ message: "Error occurred", success: false }, { status: 500 });
    } catch (error) {
        return NextResponse.json({ message: "Error scheduling post.", success: false }, { status: 500 });
    }
}

From the above code snippet:

  • api/post The endpoint accepts post content and optional publishAt time

  • If publishAt is nullthe post is published immediately. Otherwise, the time is converted to UTC for scheduling.

  • It then sends a request to the Late API using your API key and account ID to create or schedule a post on the selected social media platform.

You can also add get For the method /api/post Endpoint to retrieve already created or scheduled posts:

export async function GET() {
    try {
        const response = await fetch(
            "https://getlate.dev/api/v1/posts?platform=twitter",
            {
                method: "GET",
                headers: {
                    Authorization: `Bearer ${process.env.LATE_API_KEY}`,
                    "Content-Type": "application/json",
                },
            },
        );

        const { posts } = await response.json();

        return NextResponse.json({ posts }, { status: 200 });
    } catch (error) {
        return NextResponse.json(
            { message: "Error fetching posts.", success: false },
            { status: 500 },
        );
    }
}

Next, update handlePostSubmit In the function NewPost.tsx To send a post request /api/post. It will create or schedule the post and notify the user about the results.

const handlePostSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setDisableBtn(true);

    const now = new Date();
    const selected = date ? new Date(date) : null;
    const publishAt = !selected || selected <= now ? null : date;

    const result = await fetch("/api/post", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ content, publishAt }),
    });

    const { message, success } = await result.json();

    if (success) {
        setContent("");
        setDate("");
        alert("Success: " + message);
    } else {
        alert("Error: " + message);
    }

    setDisableBtn(false);
};

Finally, fetch all scheduled or published posts and submit them PostsQueue Ingredients:

const fetchScheduledPosts = useCallback(async () => {
    try {
        const response = await fetch("/api/post", {
            method: "GET",
            headers: { "Content-Type": "application/json" },
        });
        const data = await response.json();
        setPosts(data.posts);
        setLoading(false);
    } catch (error) {
        console.error("Error fetching scheduled posts:", error);
        setLoading(false);
    }
}, ());

useEffect(() => {
    fetchScheduledPosts();
}, (fetchScheduledPosts));

🎉 Congratulations! You have successfully built an AI-powered social media post scheduler using Next.js, Gemini API, and Late API.

The source code for this tutorial is available GitHub.

https://www.youtube.com/watch?v=PW2GU3R8BTS

The result

In this tutorial, you learned how to create and schedule social media posts across multiple platforms using the same scheduling platform, Late, and how to generate AI content using the Gemini API.

Late API Social media is a powerful tool for automating tasks, posting at specific intervals, managing multiple accounts, and tracking analytics. By combining this with automation tools like Gemini and generative AI models like N8N or Zapier, you can create automated workflows that keep your audience engaged with minimal effort.

Gemini API Makes it easy to integrate AI-powered text, images, or code generation directly into your applications, opening up a wide range of creative possibilities.

Thank you for reading! 🎉

You may also like

Leave a Comment

At Skillainest, we believe the future belongs to those who embrace AI, upgrade their skills, and stay ahead of the curve.

Get latest news

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

@2025 Skillainest.Designed and Developed by Pro