Skip to content

GDScript (Godot) SDK

Install from the Godot Asset Library:

  1. Open your Godot project
  2. Go to AssetLib tab
  3. Search for “Sieve Moderation”
  4. Click Install
extends Node
var sieve = SieveClient.new("mod_live_your_key")
func _ready():
add_child(sieve)
func moderate_chat(message: String, username: String):
var result = await sieve.moderate_text(message, "chat", username)
match result.action:
"block":
show_warning("Message blocked: " + result.primary_category)
"flag":
send_message(message) # Show but log
"allow":
send_message(message)

Until the addon is available, use Godot’s HTTPRequest node to call the Sieve API:

extends Node
const API_URL = "https://api.getsieve.dev/v1/moderate/text"
var api_key = "mod_live_your_key" # Load from config in production
func moderate_message(message: String, username: String) -> void:
var http = HTTPRequest.new()
add_child(http)
http.request_completed.connect(_on_moderation_response.bind(http, message))
var headers = [
"Authorization: Bearer " + api_key,
"Content-Type: application/json"
]
var body = JSON.stringify({
"text": message,
"context": "chat",
"username": username
})
http.request(API_URL, headers, HTTPClient.METHOD_POST, body)
func _on_moderation_response(result: int, response_code: int,
headers: PackedStringArray, body: PackedByteArray,
http: HTTPRequest, original_message: String) -> void:
http.queue_free()
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
# Fail open -- show the message if API is unreachable
_display_message(original_message)
return
var json = JSON.parse_string(body.get_string_from_utf8())
match json["action"]:
"block":
_show_blocked_warning(json["primary_category"])
"flag":
_display_message(original_message)
_log_flagged(json)
"allow":
_display_message(original_message)
func _display_message(message: String) -> void:
# Add to your chat UI
pass
func _show_blocked_warning(category: String) -> void:
# Show warning to the player
pass
func _log_flagged(result: Dictionary) -> void:
# Log flagged content for review
pass
# SieveModeration.gd -- Add as an Autoload in Project Settings
extends Node
const API_URL = "https://api.getsieve.dev/v1/moderate/text"
var api_key: String
signal moderation_complete(original_text: String, result: Dictionary)
func _ready():
# Load API key from a config file (never hardcode in production)
var config = ConfigFile.new()
config.load("user://sieve.cfg")
api_key = config.get_value("api", "key", "")
func moderate(text: String, context: String = "chat",
username: String = "") -> void:
var http = HTTPRequest.new()
add_child(http)
http.request_completed.connect(
_on_response.bind(http, text))
var headers = [
"Authorization: Bearer " + api_key,
"Content-Type: application/json"
]
var body = JSON.stringify({
"text": text,
"context": context,
"username": username
})
http.request(API_URL, headers, HTTPClient.METHOD_POST, body)
func _on_response(result: int, code: int,
headers: PackedStringArray, body: PackedByteArray,
http: HTTPRequest, original_text: String) -> void:
http.queue_free()
if result != HTTPRequest.RESULT_SUCCESS or code != 200:
moderation_complete.emit(original_text, {"action": "allow"})
return
var json = JSON.parse_string(body.get_string_from_utf8())
moderation_complete.emit(original_text, json)
# ChatUI.gd -- Connect to the autoload signal
extends Control
func _ready():
SieveModeration.moderation_complete.connect(_on_moderation)
func _on_send_pressed():
var message = $LineEdit.text
SieveModeration.moderate(message, "chat", Global.player_name)
$LineEdit.clear()
func _on_moderation(text: String, result: Dictionary):
match result["action"]:
"block":
$WarningLabel.text = "Message blocked"
$WarningLabel.visible = true
_:
add_chat_message(text)

Moderate player display names during character creation or name changes:

func _on_name_submit_pressed():
var display_name = $NameInput.text
var http = HTTPRequest.new()
add_child(http)
http.request_completed.connect(_on_name_check.bind(http, display_name))
var headers = [
"Authorization: Bearer " + api_key,
"Content-Type: application/json"
]
var body = JSON.stringify({
"text": display_name,
"context": "username"
})
http.request(API_URL, headers, HTTPClient.METHOD_POST, body)
func _on_name_check(result: int, code: int,
headers: PackedStringArray, body: PackedByteArray,
http: HTTPRequest, name: String):
http.queue_free()
var json = JSON.parse_string(body.get_string_from_utf8())
if json["action"] != "allow":
$ErrorLabel.text = "That name is not allowed. Please choose another."
$ErrorLabel.visible = true
else:
accept_name(name)
  • Fire and forget: Send the moderation request when the player submits a message. Display it immediately and retroactively hide it if blocked. Most players won’t notice the sub-200ms window.
  • Preemptive allow: For Tier 0 catches (60-70% of requests), the response comes back in under 5ms — effectively instant.
  • Timeout: Set a 1-2 second timeout on the HTTPRequest. If moderation doesn’t respond, fail open.
# Fire-and-forget pattern
func send_chat(message: String):
# Show immediately
add_chat_bubble(message, Global.player_name)
# Moderate async
SieveModeration.moderate(message, "chat", Global.player_name)
func _on_moderation(text: String, result: Dictionary):
if result["action"] == "block":
remove_chat_bubble(text)
show_warning("Your message was removed.")