Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The API is split into two parts:
- `TelegramStrategy`
- `DevtoStrategy`
- `NostrStrategy` (requires Node.js v22+)
- `InstagramStrategy` (requires an image)

Each strategy requires its own parameters that are specific to the service. If you only want to post to a particular service, you can just directly use the strategy for that service.

Expand All @@ -46,6 +47,7 @@ import {
TelegramStrategy,
DevtoStrategy,
NostrStrategy,
InstagramStrategy,
} from "@humanwhocodes/crosspost";

// Note: Use an app password, not your login password!
Expand Down Expand Up @@ -102,6 +104,12 @@ const nostr = new NostrStrategy({
relays: ["wss://relay.example.com", "wss://relay2.example.com"],
});

// Note: Access token and account ID required; an image is required when posting
const instagram = new InstagramStrategy({
accessToken: "your-access-token",
accountId: "your-instagram-account-id",
});

// create a client that will post to all services
const client = new Client({
strategies: [
Expand All @@ -114,6 +122,7 @@ const client = new Client({
telegram,
devto,
nostr,
instagram,
],
});

Expand Down Expand Up @@ -185,6 +194,7 @@ Usage: crosspost [options] ["Message to post."]
--telegram Post to Telegram.
--slack, -s Post to Slack.
--nostr, -n Post to Nostr.
--instagram, -i Post to Instagram.
--mcp Start MCP server.
--file The file to read the message from.
--image The image file to upload with the message.
Expand Down Expand Up @@ -247,6 +257,9 @@ Each strategy requires a set of environment variables in order to execute:
- Nostr
- `NOSTR_PRIVATE_KEY`
- `NOSTR_RELAYS`
- Instagram
- `INSTAGRAM_ACCESS_TOKEN`
- `INSTAGRAM_ACCOUNT_ID`

Tip: You can load environment variables from a `.env` file by setting the environment variable `CROSSPOST_DOTENV`. Set it to `1` to use `.env` in the current working directory, or set it to a specific filepath to use a different location.

Expand Down Expand Up @@ -507,6 +520,18 @@ Nostr posts are "short text notes" (kind 1 events) with a 280 character limit. I

**Security:** Keep your private key secure and never share it. Consider using a dedicated key for crossposting rather than your main Nostr identity key.

### Instagram

To enable posting to Instagram, you need an Instagram professional (Business or Creator) account connected to a Facebook Page, along with a Meta app that has the Instagram Graph API enabled:

1. Convert your Instagram account to a Business or Creator account and connect it to a Facebook Page.
2. Create an app at [Meta for Developers](https://developers.facebook.com/) and add the Instagram Graph API product.
3. Request the `instagram_basic`, `instagram_content_publish`, and `pages_show_list` permissions.
4. Generate a long-lived user access token with those permissions and use it as the value for the `INSTAGRAM_ACCESS_TOKEN` environment variable.
5. Retrieve your Instagram professional account ID (for example, via `GET /me/accounts` followed by `GET /{page-id}?fields=instagram_business_account`) and use it as the value for the `INSTAGRAM_ACCOUNT_ID` environment variable.

**Important:** Instagram requires an image to publish a post, so you must provide at least one image (PNG or JPEG). When multiple images are provided, only the first one is used. The message is used as the post caption (maximum 2200 characters).

## License

Copyright 2024-2025 Nicholas C. Zakas
Expand Down
13 changes: 13 additions & 0 deletions src/bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
TelegramStrategy,
SlackStrategy,
NostrStrategy,
InstagramStrategy,
} from "./index.js";
import { CrosspostMcpServer } from "./mcp-server.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
Expand Down Expand Up @@ -66,6 +67,7 @@ const options = {
telegram: { type: booleanType },
slack: { type: booleanType, short: "s" },
nostr: { type: booleanType, short: "n" },
instagram: { type: booleanType, short: "i" },
mcp: { type: booleanType },
file: { type: stringType },
image: { type: stringType },
Expand Down Expand Up @@ -104,6 +106,7 @@ if (
!flags.telegram &&
!flags.slack &&
!flags.nostr &&
!flags.instagram &&
!flags.mcp)
) {
console.log('Usage: crosspost [options] ["Message to post."]');
Expand All @@ -117,6 +120,7 @@ if (
console.log("--telegram Post to Telegram.");
console.log("--slack, -s Post to Slack.");
console.log("--nostr, -n Post to Nostr.");
console.log("--instagram, -i Post to Instagram.");
console.log("--mcp Start MCP server.");
console.log("--file The file to read the message from.");
console.log("--image The image file to upload with the message.");
Expand Down Expand Up @@ -258,6 +262,15 @@ if (flags.nostr) {
);
}

if (flags.instagram) {
strategies.push(
new InstagramStrategy({
accessToken: env.require("INSTAGRAM_ACCESS_TOKEN"),
accountId: env.require("INSTAGRAM_ACCOUNT_ID"),
}),
);
}

//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ export {
NostrEvent,
NostrEventResponse,
} from "./strategies/nostr.js";
export {
InstagramStrategy,
InstagramOptions,
InstagramContainerResponse,
InstagramPublishResponse,
InstagramMediaResponse,
InstagramErrorResponse,
} from "./strategies/instagram.js";
export { Client, ClientOptions, Strategy } from "./client.js";
Loading