Community-Powered Free AI Tools, TTS and APIs for Twitch Streamers
Community-Powered Free AI Tools, TTS and APIs for Twitch Streamers

How to Generate AI Images in Streamer.bot With a Custom Script

Learn how to generate free AI images for your Twitch stream directly inside Streamer.bot, by adding a custom Execute Code script, no third party middleware required.
Home How-To Guides How to Generate AI Images in Streamer.bot With a Custom Script

PotatoHotDog offers a free Generate AI Images API that you can call directly from Streamer.bot, without needing any third party middleware. This guide shows you how to add a small custom C# script to a Streamer.bot Execute Code sub action that generates an AI image from a text prompt and downloads it to disk.

The script only needs your PotatoHotDog API key and a prompt describing the image you want generated, and it saves the downloaded image into a dedicated folder inside your Streamer.bot install directory.

Prepare an API key

If you don't already have one, generate an API key from your dashboard and keep it ready, you will need it in the next step.

Go to API Keys Generate an API key in the PotatoHotDog dashboard

Prerequisite Arguments

In order to generate an AI image, two arguments need to be specified in Streamer.bot before the Execute Code sub action runs. Or, in other words, these two things need to be specified:

  • An API key.
  • The prompt instructions describing the image you want to generate.

These correspond to the following Streamer.bot arguments:

  • potatoKey
  • potatoInstructions

You specify arguments in your action by right clicking on Sub Actions, then selecting Add, Core, Arguments, and finally Set Argument.

Add a Set Argument sub action in Streamer.bot

Adding an Execute Code action in Streamer.bot

Open Streamer.bot and go to the Actions tab. Create a new action, or open an existing one, and give it a name you will recognize later, such as "PotatoHotDog AI Image".

With your action selected, click Add under Sub Actions, then choose Core followed by Execute C# Code. This adds a sub action where you can paste in raw C# code that Streamer.bot compiles and runs on the fly.

Add an Execute C# Code sub action in Streamer.bot

Paste the script below into the code editor. It reads the potatoKey and potatoInstructions arguments, calls our Generate AI Image API to generate the image and retrieve its URL, and then downloads the resulting image into a folder called temp_potatohotdog_images inside your Streamer.bot install directory.

using System; using System.IO; using System.Net.Http; using Newtonsoft.Json.Linq; public class CPHInline { // Tracks the version of this script for troubleshooting and support. private const string VERSION = "1.0.0"; // Base URL for the endpoint that generates an AI image. private const string BASE_URL_GENERATE = "https://api-generate-image-v1.potatohotdog.com/"; // Tracks the next numbered log argument. private int logIndex = 0; // Reuses one HTTP client for all API requests. private static readonly HttpClient httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; // Adds a log message as a numbered action argument. private void Log(string message) { // Stores the message under a numbered key. CPH.SetArgument($"potatoLog{logIndex}", message); // Advances the log index for the next message. logIndex++; // Keeps the total log count in sync. CPH.SetArgument("potatoLogCount", logIndex); } // Ensures a required action argument exists and is not empty. private bool RequireArgument(string name, out string value) { // Fails when the argument is missing or blank. if (!CPH.TryGetArg(name, out value) || string.IsNullOrWhiteSpace(value)) { value = ""; return false; } return true; } // URL-encodes a value so it can safely be used in a query string. private string EncodeUrlValue(string value) { // Escapes reserved characters for safe use in a URL. return Uri.EscapeDataString(value); } // Performs an HTTP GET request and returns the response body. private string HttpGet(string url) { try { Log($"GET {url}"); // Sends the HTTP request synchronously. HttpResponseMessage response = httpClient.GetAsync(url).GetAwaiter().GetResult(); // Reads the complete response body. string responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); Log($"HTTP status: {(int)response.StatusCode} {response.ReasonPhrase}"); // Stops when the server returns an unsuccessful status code. if (!response.IsSuccessStatusCode) { Log($"Error: HTTP request failed with status {(int)response.StatusCode} {response.ReasonPhrase}."); // Logs the server error response when available. if (!string.IsNullOrWhiteSpace(responseBody)) { Log($"Error response: {responseBody}"); } return null; } Log($"Received {responseBody.Length} characters."); return responseBody; } catch (Exception exception) { // Logs network, timeout, and other HTTP-related exceptions. Log($"Error: HTTP request failed: {exception.Message}"); return null; } } // Downloads a file from a URL and saves it to disk. private bool DownloadFile(string url, string destinationPath) { try { Log($"Downloading image from \"{url}\"."); Log($"Saving image to \"{destinationPath}\"."); // Sends the image download request. HttpResponseMessage response = httpClient.GetAsync(url).GetAwaiter().GetResult(); Log($"Image download HTTP status: {(int)response.StatusCode} {response.ReasonPhrase}"); // Reads the complete image response into memory. byte[] fileData = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); // Stops when the image server returns an unsuccessful status. if (!response.IsSuccessStatusCode) { Log($"Error: Image download failed with status {(int)response.StatusCode} {response.ReasonPhrase}."); return false; } // Rejects an empty image response. if (fileData == null || fileData.Length == 0) { Log("Error: The downloaded image file is empty."); return false; } // Writes the downloaded image bytes to the destination file. File.WriteAllBytes(destinationPath, fileData); Log($"Downloaded {fileData.Length} image bytes."); // Confirms that the image file now exists on disk. if (!File.Exists(destinationPath)) { Log("Error: The image download completed, but the file does not exist on disk."); return false; } // Reports the final file size from disk. FileInfo fileInfo = new FileInfo(destinationPath); Log($"Image file saved successfully. File size: {fileInfo.Length} bytes."); return true; } catch (Exception exception) { // Logs download, filesystem, and permission errors. Log($"Error: Could not download the image file: {exception.Message}"); return false; } } // Extracts a required string value from a JSON response. private bool TryGetJsonString(string json, string propertyName, out string value) { value = ""; try { // Parses the response body as a JSON object. JObject jsonObject = JObject.Parse(json); // Retrieves the requested JSON property. JToken property = jsonObject[propertyName]; if (property == null) { Log($"Error: JSON response does not contain \"{propertyName}\"."); return false; } value = property.ToString(); // Rejects empty JSON string values. if (string.IsNullOrWhiteSpace(value)) { Log($"Error: JSON property \"{propertyName}\" is empty."); value = ""; return false; } return true; } catch (Exception exception) { // Logs malformed JSON and property conversion errors. Log($"Error: Could not parse JSON property \"{propertyName}\": {exception.Message}"); return false; } } // Creates and returns the dedicated PotatoImage folder. private string GetImageFolder() { // Uses Streamer.bot's application directory instead of the process working directory. string streamerBotFolder = AppDomain.CurrentDomain.BaseDirectory; // Places generated image files inside a dedicated subfolder. string imageFolder = Path.Combine(streamerBotFolder, "temp_potatohotdog_images"); Log($"Streamer.bot folder: \"{streamerBotFolder}\"."); Log($"Image folder: \"{imageFolder}\"."); // Creates the image folder if it does not already exist. if (!Directory.Exists(imageFolder)) { Log("Image folder does not exist. Creating it..."); Directory.CreateDirectory(imageFolder); Log("Image folder created."); } else { Log("Image folder already exists."); } return imageFolder; } // Runs the main PotatoHotdog AI image action. public bool Execute() { // Resets log numbering for this execution. logIndex = 0; CPH.SetArgument("potatoLogCount", 0); Log("Starting script..."); // Logs the script version so runs can be tracked over time. Log($"Version: {VERSION}"); // Retrieves the PotatoHotdog API key. if (!RequireArgument("potatoKey", out string potatoKey)) { Log("Error: potatoKey variable is missing. Please login to potatohotdog.com, generate an API key, create a set variable action and save the variable \"potatoKey\" with your key."); return false; } // Retrieves the prompt instructions describing the image to generate. if (!RequireArgument("potatoInstructions", out string potatoInstructions)) { Log("Error: potatoInstructions variable is missing. Create a set variable action and save the variable \"potatoInstructions\" with a description of the image you want generated."); return false; } // Logs the non-secret input values. Log("potatoKey was provided."); Log($"potatoInstructions=\"{potatoInstructions}\""); // Builds the API URL used to generate the AI image. string generateUrl = BASE_URL_GENERATE + "?key=" + EncodeUrlValue(potatoKey) + "&instructions=" + EncodeUrlValue(potatoInstructions); // Requests generation of the AI image. string generateJson = HttpGet(generateUrl); if (generateJson == null) { Log("Error: Failed to generate the AI image."); return false; } Log($"Generate response: {generateJson}"); // Extracts the generated item's ID, reused below as the local filename. if (!TryGetJsonString(generateJson, "itemID", out string itemID)) { Log("Error: Could not retrieve itemID from the generate response."); return false; } Log($"itemID=\"{itemID}\""); // Logs the generation duration when present, purely for troubleshooting. if (TryGetJsonString(generateJson, "duration", out string duration)) { Log($"duration={duration} second(s)"); } // Extracts the generated image URL from the response. if (!TryGetJsonString(generateJson, "imageURL", out string imageURL)) { Log("Error: Could not retrieve imageURL from the generate response."); return false; } Log($"imageURL=\"{imageURL}\""); string imageFolder; try { // Resolves and creates the dedicated PotatoImage directory. imageFolder = GetImageFolder(); } catch (Exception exception) { Log($"Error: Could not create or access the image folder: {exception.Message}"); return false; } // Reuses the item's own ID as the local filename instead of minting a new one. string imageFileName = $"{itemID}.png"; // Combines the image folder and unique filename. string imageFilePath = Path.Combine(imageFolder, imageFileName); Log($"Generated image filename: \"{imageFileName}\"."); Log($"Local image path: \"{imageFilePath}\"."); // Downloads the generated image file to the PotatoImage folder. if (!DownloadFile(imageURL, imageFilePath)) { Log("Error: Failed to download the generated AI image."); return false; } // Stores the remote image URL as a final action argument. CPH.SetArgument("potatoGeneratedImageURL", imageURL); // Stores the absolute local file path as a final action argument. CPH.SetArgument("potatoGeneratedImageFile", imageFilePath); Log($"potatoGeneratedImageURL=\"{imageURL}\""); Log($"potatoGeneratedImageFile=\"{imageFilePath}\""); Log("Finished."); return true; } }

After pasting the script, remember to click on Find Refs and Compile and make sure it compiles successfully. Save the action, then trigger it manually or bind it to a command or channel point reward to test that the image is generated correctly.

Paste the script and compile it in Streamer.bot

Inspect the downloaded image

Once the action has run, you can inspect the Action variables via the Action History to confirm everything worked as expected.

There you will find the local path where the generated image was saved on disk, inside the temp_potatohotdog_images folder in your Streamer.bot install directory.

Inspect the generated images variables in action history

Open that folder to view the downloaded image directly.

Inspect Action variables via the Action History in Streamer.bot

Troubleshooting

If the script does not behave as expected, the best way to troubleshoot it is by checking the action logs.

You can do this by inspecting your Action variables via the Action History.

Inspect Action variables via the Action History in Streamer.bot

This guide was first published 2026-07-19 and was last modified 2026-07-19.

Other Similar Guides

Here are some other how-to guides you might find useful.

How to Connect Streamer.bot to an AI
How to Connect Streamer.bot to an AI
Learn how to generate free AI (LLM) responses for your Twitch stream in Streamer.bot using a Fetch URL sub action and the PotatoHotDog Generate AI Response API, no custom script required.
Read Guide
How to Play Free TTS Audio in Streamer.bot With Dynamic Browser Sources
How to Play Free TTS Audio in Streamer.bot With Dynamic Browser Sources
Learn how to play free AI TTS (Text-to-Speech) audio for your Twitch stream in Streamer.bot using a Dynamic Browser Source and a simple Fetch URL webhook request, no custom script required.
Read Guide
How to Play Free TTS Audio in Streamer.bot With a Custom Script
How to Play Free TTS Audio in Streamer.bot With a Custom Script
Learn how to play free AI TTS (Text-to-Speech) audio for your Twitch stream directly inside Streamer.bot, by adding a custom Execute Code script, no Speaker.bot required.
Read Guide