Summary
Norway's top 10 weekly Google Trends: What Norwegians are searching for the most in the last 24 Hours!
Description
Integrating Discord with Novem Plots
This guide explains how to automatically post a Novem plot as an image to a Discord channel (or thread) every time your job runs. Follow every step in order and you'll have it working.
Step 1: Get your Discord Webhook URL
A webhook URL is a special link that lets a script post messages into a Discord channel.
- Open Discord and go to the channel you want to post in
- Click the gear icon next to the channel name to open channel settings
- Click Integrations in the left sidebar → Webhooks → New Webhook
- (If you don't see this option you don't have permission — ask a server moderator to create one for you)
- Give the webhook a name (anything you like), then click Copy Webhook URL
- Save that URL somewhere safe — you'll need it in Step 2
It will look like this:
https://discord.com/api/webhooks/123456789/abcdefg-long-token-here
Optional: posting into a Thread instead of the main channel
If you want messages to go into a specific thread rather than the main channel, you need the thread's ID:
- In Discord, go to User Settings → Advanced → turn on Developer Mode
- Right-click the thread name and click Copy Thread ID
- Save that ID — you'll use it as
discord_thread_idin Step 2
Step 2: Store your webhook URL as an Environment Variable in Novem
Environment variables are a safe way to store secrets (like passwords and tokens) outside of your code. Instead of writing the webhook URL directly in your script, you store it in Novem and your script reads it automatically at runtime.
Never paste your webhook URL directly into your script code. If you share your code, others would be able to post to your Discord.
To add environment variables to your Novem job:
- Go to your job in Novem
- Find the Environment Variables section
- Add the following variables (only
discord_webhook_urlis required):
| Variable name | What to put in it |
|---|---|
discord_webhook_url |
The full webhook URL you copied in Step 1 |
discord_thread_id |
(Optional) The thread ID if you want to post into a thread |
Your script reads these with os.environ.get("discord_webhook_url") — you will see this in the code below.
Step 3: Fetch the plot image from Novem
After your job updates the plot data, Novem needs a few seconds to re-render it. This function waits 8 seconds then downloads the plot as a PNG image and returns its raw binary contents:
import time, requests
def fetch_plot_image(api_base: str, token: str, plot_name: str) -> bytes:
time.sleep(8) # wait for Novem to finish rendering the updated plot
url = f"{api_base}/vis/plots/{plot_name}/files/plot.png"
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=60)
resp.raise_for_status() # raises an error if the request failed
return resp.content # returns the raw PNG bytes (binary image data)
Note:
api_baseandtoken(your Novem API token) are automatically available as environment variables inside every Novem job — you don't need to set them yourself.
Step 4: Post the image to Discord
This function takes the raw PNG bytes from Step 3 and sends them to Discord along with a text message:
import json, requests
def post_to_discord(webhook_url: str, image_bytes: bytes, plot_name: str, thread_id: str = ""):
# image_bytes: the raw PNG binary returned by fetch_plot_image() — sent as the file attachment
# thread_id: leave as "" to post in the main channel, or pass a thread ID to post in a thread
url = f"{webhook_url}?thread_id={thread_id}" if thread_id else webhook_url
# This is the text message that appears above the image in Discord.
# Replace the content below with whatever you want to say.
# Replace {your_username} with your actual Novem username.
content = (
f"New chart just posted!\n"
f"https://novem.io/u/{{your_username}}/p/{plot_name}"
)
resp = requests.post(
url,
files={"file": (f"{plot_name}.png", image_bytes, "image/png")},
data={"payload_json": json.dumps({"content": content})},
timeout=30,
)
resp.raise_for_status() # raises an error if Discord rejected the request
Important: Discord requires both a
filefield and apayload_jsonfield sent together. Sending only JSON (without the file) will not attach the image.
Step 5: Wire it all together
Here is a complete working script you can copy and adapt. Replace "your-plot-name" with your actual Novem plot name:
import os, time, json, requests
PLOT_NAME = "your-plot-name" # ← change this to your plot name
def fetch_plot_image(api_base, token, plot_name):
time.sleep(8)
url = f"{api_base}/vis/plots/{plot_name}/files/plot.png"
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=60)
resp.raise_for_status()
return resp.content
def post_to_discord(webhook_url, image_bytes, plot_name, thread_id=""):
url = f"{webhook_url}?thread_id={thread_id}" if thread_id else webhook_url
content = (
f"New chart just posted!\n"
f"https://novem.io/u/your_username/p/{plot_name}" # ← replace your_username
)
resp = requests.post(
url,
files={"file": (f"{plot_name}.png", image_bytes, "image/png")},
data={"payload_json": json.dumps({"content": content})},
timeout=30,
)
resp.raise_for_status()
def main():
# These are automatically available inside every Novem job
token = os.environ.get("novem_token", "")
api_base = os.environ.get("api_base", "https://api.novem.io/v1")
# These you set yourself in the job's Environment Variables (see Step 2)
webhook_url = os.environ.get("discord_webhook_url", "")
thread_id = os.environ.get("discord_thread_id", "")
if not webhook_url:
print("No discord_webhook_url set — skipping Discord post.")
return
# 1. (Your code to update the plot data goes here)
# 2. Fetch the rendered plot image
image_bytes = fetch_plot_image(api_base, token, PLOT_NAME)
# 3. Post it to Discord
post_to_discord(webhook_url, image_bytes, PLOT_NAME, thread_id=thread_id)
print("Posted to Discord successfully.")
if __name__ == "__main__":
main()
Summary of what each piece does
1. Your script updates the plot data in Novem
2. Wait 8 seconds for Novem to re-render the plot as a PNG
3. Download the PNG from Novem → stored in image_bytes
4. Send image_bytes + a text message to your Discord webhook URL