social Module (stx.social)

Socialia - Unified social media management: posting, analytics, and insights.

class scitex.social.Twitter(consumer_key=None, consumer_secret=None, access_token=None, access_token_secret=None, *, session_factory=None, read_backend=None, read_username=None)[source]

Bases: TwitterGrowthMixin, _Base

Twitter/X API v2 client using OAuth 1.0a.

platform_name: str = 'twitter'
MAX_TWEET_LENGTH = 280
POST_ENDPOINT = 'https://api.x.com/2/tweets'
DELETE_ENDPOINT = 'https://api.x.com/2/tweets/{tweet_id}'
ME_ENDPOINT = 'https://api.x.com/2/users/me'
USER_TWEETS_ENDPOINT = 'https://api.x.com/2/users/{user_id}/tweets'
USER_MENTIONS_ENDPOINT = 'https://api.x.com/2/users/{user_id}/mentions'
SEARCH_ENDPOINT = 'https://api.x.com/2/tweets/search/recent'
MEDIA_UPLOAD_ENDPOINT = 'https://upload.twitter.com/1.1/media/upload.json'
USER_BY_USERNAME_ENDPOINT = 'https://api.x.com/2/users/by/username/{username}'
FOLLOW_ENDPOINT = 'https://api.x.com/2/users/{source_user_id}/following'
UNFOLLOW_ENDPOINT = 'https://api.x.com/2/users/{source_user_id}/following/{target_user_id}'
validate_credentials()[source]

Check if all credentials are set.

Return type:

bool

validate_read_credentials()[source]

Check if read operations can use OAuth or the optional read backend.

Return type:

bool

upload_media(file_path)[source]

Upload media file to Twitter (images and videos).

Automatically detects file type and uses: - Simple upload for images (jpg, png, gif, webp) - Chunked upload for videos (mp4, mov)

Parameters:

file_path (str) – Path to media file

Return type:

dict

Returns:

dict with ‘success’, ‘media_id’ or ‘error’

post(text, reply_to=None, quote_tweet_id=None, media_ids=None)[source]

Post a tweet.

Parameters:
  • text (str) – Tweet content (max 280 chars standard, 25000 premium)

  • reply_to (Optional[str]) – Tweet ID to reply to

  • quote_tweet_id (Optional[str]) – Tweet ID to quote

  • media_ids (Optional[list]) – List of media IDs from upload_media()

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘url’ or ‘error’

delete(post_id)[source]

Delete a tweet.

Parameters:

post_id (str) – Tweet ID to delete

Return type:

dict

Returns:

dict with ‘success’ and ‘deleted’ or ‘error’

post_thread(tweets)[source]

Post a thread of tweets.

Parameters:

tweets (list[str]) – List of tweet texts

Return type:

dict

Returns:

dict with ‘success’, ‘ids’, ‘urls’ or ‘error’

me()[source]

Get authenticated user information.

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘username’, ‘name’ or ‘error’

feed(limit=10)[source]

Get user’s recent tweets.

Parameters:

limit (int) – Maximum number of tweets to return (max 100)

Return type:

dict

Returns:

dict with ‘success’, ‘tweets’ list or ‘error’

mentions(limit=10)[source]

Get recent mentions of the user.

Parameters:

limit (int) – Maximum number of mentions to return (max 100)

Return type:

dict

Returns:

dict with ‘success’, ‘mentions’ list or ‘error’

replies(limit=10)[source]

Get recent replies to the user’s tweets.

Parameters:

limit (int) – Maximum number of replies to return (max 100)

Return type:

dict

Returns:

dict with ‘success’, ‘replies’ list or ‘error’

class scitex.social.LinkedIn(access_token=None, client_id=None, client_secret=None, *, http=None)[source]

Bases: _Base

LinkedIn API client using OAuth 2.0.

platform_name: str = 'linkedin'
BASE_URL = 'https://api.linkedin.com/v2'
ME_ENDPOINT = 'https://api.linkedin.com/v2/me'
USERINFO_ENDPOINT = 'https://api.linkedin.com/v2/userinfo'
UGC_POSTS_ENDPOINT = 'https://api.linkedin.com/v2/ugcPosts'
POSTS_ENDPOINT = 'https://api.linkedin.com/v2/posts'
SHARES_ENDPOINT = 'https://api.linkedin.com/v2/shares'
validate_credentials()[source]

Check if access token is set.

Return type:

bool

post(text, visibility='PUBLIC')[source]

Post to LinkedIn feed.

Parameters:
  • text (str) – Post content

  • visibility (str) – PUBLIC, CONNECTIONS, or LOGGED_IN

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘url’ or ‘error’

delete(post_id)[source]

Delete a LinkedIn post.

Note: LinkedIn API has limited delete support.

Parameters:

post_id (str) – Post URN/ID to delete

Return type:

dict

Returns:

dict with ‘success’ or ‘error’

get_token_info()[source]

Get information about the current access token.

Return type:

dict

me()[source]

Get authenticated user information.

Return type:

dict

Returns:

dict with ‘success’, user info or ‘error’

feed(limit=10)[source]

Get user’s recent posts/shares.

Note: LinkedIn API has limited support for reading posts. Requires r_organization_social or w_member_social scopes.

Parameters:

limit (int) – Maximum number of posts to return

Return type:

dict

Returns:

dict with ‘success’, ‘posts’ list or ‘error’

class scitex.social.Reddit(client_id=None, client_secret=None, username=None, password=None, user_agent=None)[source]

Bases: _Base

Reddit API client using PRAW (Python Reddit API Wrapper).

platform_name = 'reddit'
validate_credentials()[source]

Check if all credentials are set.

Return type:

bool

post(text, subreddit='test', title=None, url=None, flair_id=None)[source]

Post to a subreddit.

Parameters:
  • text (str) – Post body (for self posts) or ignored for link posts

  • subreddit (str) – Target subreddit name (without r/)

  • title (Optional[str]) – Post title (required for Reddit)

  • url (Optional[str]) – URL for link posts (makes it a link post instead of self post)

  • flair_id (Optional[str]) – Optional flair ID

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘url’ or ‘error’

delete(post_id)[source]

Delete a Reddit post.

Parameters:

post_id (str) – Reddit submission ID

Return type:

dict

Returns:

dict with ‘success’ or ‘error’

comment(post_id, text)[source]

Add a comment to a post.

Parameters:
  • post_id (str) – Reddit submission ID

  • text (str) – Comment text

Return type:

dict

Returns:

dict with ‘success’, ‘id’ or ‘error’

me()[source]

Get authenticated user information.

Return type:

dict

Returns:

dict with ‘success’, user info or ‘error’

feed(limit=10)[source]

Get user’s recent submissions.

Parameters:

limit (int) – Maximum number of posts to return

Return type:

dict

Returns:

dict with ‘success’, ‘posts’ list or ‘error’

mentions(limit=10)[source]

Get recent inbox mentions.

Parameters:

limit (int) – Maximum number of mentions to return

Return type:

dict

Returns:

dict with ‘success’, ‘mentions’ list or ‘error’

update(post_id, text)[source]

Edit a Reddit post.

Parameters:
  • post_id (str) – Reddit submission ID

  • text (str) – New text content

Return type:

dict

Returns:

dict with ‘success’ or ‘error’

class scitex.social.Slack(bot_token=None, default_channel=None)[source]

Bases: _Base

Slack Web API client for posting to channels.

platform_name: str = 'slack'
API_BASE = 'https://slack.com/api'
POST_MESSAGE_ENDPOINT = 'https://slack.com/api/chat.postMessage'
DELETE_MESSAGE_ENDPOINT = 'https://slack.com/api/chat.delete'
UPDATE_MESSAGE_ENDPOINT = 'https://slack.com/api/chat.update'
CONVERSATIONS_HISTORY_ENDPOINT = 'https://slack.com/api/conversations.history'
AUTH_TEST_ENDPOINT = 'https://slack.com/api/auth.test'
USERS_INFO_ENDPOINT = 'https://slack.com/api/users.info'
__init__(bot_token=None, default_channel=None)[source]

Initialize Slack client.

Parameters:
  • bot_token (Optional[str]) – Slack Bot Token (xoxb-…)

  • default_channel (Optional[str]) – Default channel ID to post to

validate_credentials()[source]

Check if bot token is set.

Return type:

bool

post(text, channel=None, thread_ts=None, unfurl_links=True, unfurl_media=True)[source]

Post a message to a Slack channel.

Parameters:
  • text (str) – Message content (supports Slack markdown)

  • channel (Optional[str]) – Channel ID (uses default if not specified)

  • thread_ts (Optional[str]) – Thread timestamp to reply to

  • unfurl_links (bool) – Enable link previews

  • unfurl_media (bool) – Enable media previews

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘ts’, ‘channel’ or ‘error’

delete(post_id, channel=None)[source]

Delete a message from a Slack channel.

Parameters:
  • post_id (str) – Message timestamp (ts)

  • channel (Optional[str]) – Channel ID (uses default if not specified)

Return type:

dict

Returns:

dict with ‘success’, ‘deleted’ or ‘error’

update(post_id, text, channel=None)[source]

Update an existing message.

Parameters:
  • post_id (str) – Message timestamp (ts)

  • text (str) – New message content

  • channel (Optional[str]) – Channel ID (uses default if not specified)

Return type:

dict

Returns:

dict with ‘success’, ‘ts’ or ‘error’

feed(limit=10, channel=None)[source]

Get recent messages from a channel.

Parameters:
  • limit (int) – Maximum number of messages to return

  • channel (Optional[str]) – Channel ID (uses default if not specified)

Return type:

dict

Returns:

dict with ‘success’, ‘messages’ list or ‘error’

me()[source]

Get authenticated bot info.

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘name’, ‘team’ or ‘error’

post_thread(messages, channel=None)[source]

Post a thread of messages.

Parameters:
  • messages (list) – List of message texts

  • channel (Optional[str]) – Channel ID (uses default if not specified)

Return type:

dict

Returns:

dict with ‘success’, ‘ts_list’, ‘thread_ts’ or ‘error’

class scitex.social.YouTube(client_secrets_file=None, token_file=None)[source]

Bases: _Base

YouTube API client for video uploads and management.

Environment Variables:

YOUTUBE_CLIENT_SECRETS_FILE: Path to OAuth client secrets JSON YOUTUBE_TOKEN_FILE: Path to store OAuth tokens (default: runtime/youtube_token.json)

platform_name: str = 'youtube'
__init__(client_secrets_file=None, token_file=None)[source]

Initialize YouTube client.

Parameters:
  • client_secrets_file (Optional[str]) – Path to OAuth client secrets JSON from Google Console

  • token_file (Optional[str]) – Path to store/load OAuth tokens

validate_credentials()[source]

Check if credentials are available.

Return type:

bool

post(text, video_path=None, title=None, description=None, tags=None, category_id='22', privacy_status='public', thumbnail_path=None)[source]

Upload a video or create a community post.

Parameters:
  • text (str) – Description text (or community post text if no video)

  • video_path (Optional[str]) – Path to video file (required for video upload)

  • title (Optional[str]) – Video title (uses first line of text if not provided)

  • description (Optional[str]) – Video description (uses text if not provided)

  • tags (Optional[list]) – List of tags for the video

  • category_id (str) – YouTube category ID (default: 22 = People & Blogs)

  • privacy_status (str) – ‘public’, ‘private’, or ‘unlisted’

  • thumbnail_path (Optional[str]) – Path to custom thumbnail image

Return type:

dict

Returns:

dict with ‘success’, ‘id’, ‘url’ or ‘error’

delete(video_id)[source]

Delete a video by ID.

Parameters:

video_id (str) – YouTube video ID

Return type:

dict

Returns:

dict with ‘success’ or ‘error’

update(video_id, title=None, description=None, tags=None, privacy_status=None)[source]

Update video metadata.

Parameters:
  • video_id (str) – YouTube video ID

  • title (Optional[str]) – New title (optional)

  • description (Optional[str]) – New description (optional)

  • tags (Optional[list]) – New tags (optional)

  • privacy_status (Optional[str]) – New privacy status (optional)

Return type:

dict

Returns:

dict with ‘success’ or ‘error’

get_channel_info()[source]

Get authenticated user’s channel information.

Return type:

dict

list_videos(max_results=10)[source]

List user’s uploaded videos.

Parameters:

max_results (int) – Maximum number of videos to return

Return type:

dict

Returns:

dict with videos list or error

me()[source]

Get authenticated user’s channel information.

Return type:

dict

feed(limit=10)[source]

Get user’s recent videos.

Parameters:

limit (int) – Maximum number of videos to return

Return type:

dict

Returns:

dict with ‘success’, ‘posts’ list or ‘error’

class scitex.social.GoogleAnalytics(measurement_id=None, api_secret=None, property_id=None, *, http=None)[source]

Bases: object

Google Analytics 4 integration.

Supports:

  • Measurement Protocol (sending events)

  • Data API (retrieving metrics) - requires service account

Environment Variables (use branded prefix, e.g. SOCIALIA_):

  • GOOGLE_ANALYTICS_MEASUREMENT_ID – GA4 Measurement ID (G-XXXXXXXXXX)

  • GOOGLE_ANALYTICS_API_SECRET – Measurement Protocol API secret

  • GOOGLE_ANALYTICS_PROPERTY_ID – Property ID (numeric, for Data API)

  • GOOGLE_APPLICATION_CREDENTIALS – Path to service account JSON (for Data API)

__init__(measurement_id=None, api_secret=None, property_id=None, *, http=None)[source]

Initialize Google Analytics client.

Parameters:
  • measurement_id (Optional[str]) – GA4 Measurement ID (G-XXXXXXXXXX)

  • api_secret (Optional[str]) – Measurement Protocol API secret

  • property_id (Optional[str]) – GA4 Property ID (numeric, for Data API)

  • http (Optional[Any]) – Injectable requests-shaped HTTP client (exposes post); production code leaves this None and the requests module is used. Tests pass a hand-rolled fake.

validate_credentials()[source]

Check which features are available based on credentials.

Return type:

dict

track_event(name, params=None, client_id=None, user_id=None)[source]

Send event to Google Analytics via Measurement Protocol.

Parameters:
  • name (str) – Event name (e.g., ‘social_post’, ‘social_share’)

  • params (Optional[dict]) – Event parameters dict

  • client_id (Optional[str]) – Client ID (generated if not provided)

  • user_id (Optional[str]) – Optional user ID for cross-device tracking

Return type:

dict

Returns:

dict with ‘success’ and details

Example

ga.track_event('social_post', {
    'platform': 'twitter',
    'post_id': '123456',
    'content_length': 280,
})
track_social_post(platform, post_id, content_type='text', success=True)[source]

Track a social media post event.

Parameters:
  • platform (str) – Platform name (twitter, linkedin, reddit)

  • post_id (str) – Post ID from the platform

  • content_type (str) – Type of content (text, link, image, thread)

  • success (bool) – Whether the post was successful

Return type:

dict

Returns:

dict with tracking result

track_social_delete(platform, post_id)[source]

Track a social media delete event.

Return type:

dict

get_realtime_users()[source]

Get realtime active users (requires Data API setup).

Return type:

dict

Returns:

dict with ‘success’ and ‘active_users’ count

get_page_views(start_date='7daysAgo', end_date='today', page_path=None)[source]

Get page view metrics (requires Data API setup).

Parameters:
  • start_date (str) – Start date (YYYY-MM-DD or relative like ‘7daysAgo’)

  • end_date (str) – End date (YYYY-MM-DD or ‘today’)

  • page_path (Optional[str]) – Optional page path filter

Return type:

dict

Returns:

dict with ‘success’ and metrics

get_traffic_sources(start_date='7daysAgo', end_date='today')[source]

Get traffic source breakdown (requires Data API setup).

Return type:

dict

Returns:

dict with traffic sources and their metrics

scitex.social.move_to_scheduled(filepath)[source]

Move file from drafts/ to scheduled/ directory.

Returns new path if moved, None if no scheduled/ directory found.

Return type:

Path | None

scitex.social.move_to_posted(filepath)[source]

Move file from scheduled/ to posted/ directory.

Returns new path if moved, None if no posted/ directory found.

Return type:

Path | None

scitex.social.ensure_project_dirs(base_path)[source]

Ensure drafts/, scheduled/, posted/ directories exist.

Parameters:

base_path (Path) – Project base directory

Return type:

dict[str, Path]

Returns:

dict with ‘drafts’, ‘scheduled’, ‘posted’ paths