This guide explains how to integrate SocialStream.Ninja with Streamer.bot using WebSockets. This allows Streamer.bot to receive chat messages captured by SocialStream.Ninja and trigger custom actions based on them.
To process messages from SocialStream.Ninja, you must create an Action in Streamer.bot. SocialStream.Ninja will trigger this action for each incoming message.
using System;
using Newtonsoft.Json.Linq; // Make sure Newtonsoft.Json is referenced
public class CPHInline
{
public bool Execute()
{
// --- Get the main chatData object sent from SocialStream.Ninja ---
JObject chatData = null;
if (args.ContainsKey("chatData") && args["chatData"] is JObject)
{
chatData = (JObject)args["chatData"];
}
else
{
CPH.LogWarn("[SocialStream] Action triggered but 'chatData' argument was missing or not a JSON object.");
// Try converting if it's a string representation of JSON (less ideal)
if (args.ContainsKey("chatData") && args["chatData"] is string) {
try {
chatData = JObject.Parse((string)args["chatData"]);
} catch (Exception ex) {
CPH.LogError($"[SocialStream] Failed to parse chatData string: {ex.Message}");
return false;
}
} else {
return false; // Exit if we definitely don't have chatData
}
}
// --- Extract specific fields from the chatData object ---
string message = GetStringValue(chatData, "chatmessage", "");
string username = GetStringValue(chatData, "chatname", "Unknown User");
string userId = GetStringValue(chatData, "userid", "");
string avatar = GetStringValue(chatData, "chatimg", "");
bool isBot = GetBoolValue(chatData, "isBot", false);
string originalPlatform = GetStringValue(chatData, "originalPlatform", "unknown");
string source = GetStringValue(chatData, "source", "unknown");
// Log the received message to Streamer.bot's Action Queue logs for debugging
CPH.LogInfo($"[SocialStream][{originalPlatform}] {username}: {message}");
// --- Set arguments for subsequent sub-actions ---
CPH.SetArgument("ss_message", message);
CPH.SetArgument("ss_username", username);
CPH.SetArgument("ss_userId", userId);
CPH.SetArgument("ss_avatar", avatar);
CPH.SetArgument("ss_isBot", isBot);
CPH.SetArgument("ss_platform", originalPlatform);
CPH.SetArgument("ss_source", source);
return true;
}
// Helper methods to safely get values from JObject with specific types
private string GetStringValue(JObject obj, string key, string defaultValue)
{
try
{
if (obj != null && obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken token))
{
return token.ToString();
}
}
catch (Exception ex) {
CPH.LogWarn($"[SocialStream] Error getting value for key '{key}': {ex.Message}");
}
return defaultValue;
}
private bool GetBoolValue(JObject obj, string key, bool defaultValue)
{
try
{
if (obj != null && obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken token))
{
return token.ToObject<bool>();
}
}
catch (Exception ex) {
CPH.LogWarn($"[SocialStream] Error getting value for key '{key}': {ex.Message}");
}
return defaultValue;
}
}
When SocialStream.Ninja sends data to Streamer.bot, it passes a detailed JSON object with the following fields that you can access in your Streamer.bot actions. The example C# code above extracts these fields and makes them available as arguments.
These are the main fields available in the chatData object:
| Field Name | Type | Description | Argument Name | Example Usage |
|---|---|---|---|---|
| chatmessage | String | The actual chat message content. May contain HTML tags if textonly is false. | ss_message | %ss_message% |
| chatname | String | The display name of the user who sent the message. | ss_username | %ss_username% |
| userid | String | The unique ID of the user from the original platform. | ss_userId | %ss_userId% |
| chatimg | String | URL to the user's avatar/profile image. | ss_avatar | %ss_avatar% |
| isBot | Boolean | Flag indicating if the message was from a bot. | ss_isBot | %ss_isBot% |
| originalPlatform | String | The platform the message originated from (e.g., "youtube", "twitch", "kick", etc.). | ss_platform | %ss_platform% |
| source | String | Identifies the source as "SocialStream.Ninja". | ss_source | %ss_source% |
These additional fields may be present depending on the message type and platform:
| Field Name | Type | Description | Access in C# |
|---|---|---|---|
| contentimg | String | URL to content image, if present in the message. | GetValue<string>(chatData, "contentimg", "") |
| subtitle | String | Additional text like user status or other metadata. | GetValue<string>(chatData, "subtitle", "") |
| membership | String | Membership information, if applicable. | GetValue<string>(chatData, "membership", "") |
| hasDonation | String/Boolean | Donation information, if present. | GetValue<string>(chatData, "hasDonation", "") |
| type | String | Source type (e.g., "twitch", "youtube", "kick"). | GetValue<string>(chatData, "type", "") |
| id | String | Unique message ID from the source platform. | GetValue<string>(chatData, "id", "") |
| nameColor | String | HEX color code for the username (e.g., "#FF0000"). | GetValue<string>(chatData, "nameColor", "#FFFFFF") |
| chatbadges | String/Array | Chat badges from the source platform. | GetValue<string>(chatData, "chatbadges", "") |
| textonly | Boolean | If true, indicates that HTML has been stripped from the message. | GetValue<bool>(chatData, "textonly", false) |
| tid | String | Transaction ID used for duplicate detection. | GetValue<string>(chatData, "tid", "") |
To access fields not already extracted in the example C# code, add lines like:
// Extract additional fields as needed
string contentImage = GetValue<string>(chatData, "contentimg", "");
string subtitle = GetValue<string>(chatData, "subtitle", "");
string nameColor = GetValue<string>(chatData, "nameColor", "#FFFFFF");
// Make them available as arguments
CPH.SetArgument("ss_contentImage", contentImage);
CPH.SetArgument("ss_subtitle", subtitle);
CPH.SetArgument("ss_nameColor", nameColor);
You can add conditional logic based on the platform or other message properties:
// Example: Process messages differently based on platform
if (originalPlatform.Equals("youtube", StringComparison.OrdinalIgnoreCase))
{
// YouTube-specific processing
CPH.PlaySound("sounds/youtube_alert.mp3");
// Check for YouTube memberships
string membership = GetValue<string>(chatData, "membership", "");
if (!string.IsNullOrEmpty(membership))
{
CPH.SetArgument("ss_hasMembership", true);
CPH.SetArgument("ss_membershipInfo", membership);
CPH.LogInfo($"[YouTube Membership] {username}: {membership}");
}
}
else if (originalPlatform.Equals("twitch", StringComparison.OrdinalIgnoreCase))
{
// Twitch-specific processing
string badges = GetValue<string>(chatData, "chatbadges", "");
bool isSubscriber = badges.Contains("subscriber");
CPH.SetArgument("ss_isSubscriber", isSubscriber);
}
You can format messages for display in various ways:
// Standard format with platform
string formattedMessage = $"[{originalPlatform.ToUpper()}] {username}: {message}";
CPH.SetArgument("ss_formattedMessage", formattedMessage);
// HTML format for web display
string htmlFormat = $"<span style='color:{GetValue<string>(chatData, "nameColor", "#FFFFFF")}'>{username}</span>: {message}";
CPH.SetArgument("ss_htmlMessage", htmlFormat);
// Format for OBS Text Source
string obsText = $"{originalPlatform} | {username} says: {message}";
CPH.SetArgument("ss_obsText", obsText);
Limitation: Sending messages from an external application (like SocialStream.Ninja) via WebSocket to directly appear within Streamer.bot's own "Chat" tab or integrated overlays (using the `ChatMessage` request type) is currently **not a reliably supported feature** of the Streamer.bot WebSocket server.
While the WebSocket specification includes a `ChatMessage` request, its behaviour for *injecting* messages *into* Streamer.bot's display seems inconsistent or non-functional for this purpose. Its primary role is typically to report messages *from* Streamer.bot *to* connected clients.
Therefore, **you MUST use the Action ID method** described above to send message data to Streamer.bot. You can then use sub-actions within Streamer.bot (like sending a message to your Twitch/YouTube channel) if you want the message content to appear in chat overlays that monitor those platforms.
Please do not report issues related to messages not appearing directly in Streamer.bot's chat tab when *not* using an Action ID, as this relies on functionality that may need to be specifically added or modified by the Streamer.bot developers.
For help on using Streamer.bot, please contact the Streamer.bot's support, as I do have on experience with using it. Also, Streamer.bot's code does not appear to be open-sourced, so if you wish to have additional Social Stream Ninja supported within Streamer.bot, you'll need to make requests to them.
-steve