Godot Quick Start
Integrate Indieop API into your Godot games using GDScript.
Prerequisites
Before you begin, make sure you have:
- Created an Indieop account
- Created a game and obtained your API key from the game settings
- Godot 3.5+ or Godot 4.x installed
Overview
This guide shows you how to send player feedback and form submissions from your Godot game to the Indieop API using GDScript. The implementation uses Godot's built-in HTTPRequest node.
Implementation
Step 1: Create the API Client Script
Create a new script called indieop_client.gd:
extends Node
class_name IndieOpClient
const BASE_URL = "https://indieop.com/api/sdk"
var api_key: String
var http_request: HTTPRequest
signal submission_completed(success: bool, message: String)
func _init(p_api_key: String):
api_key = p_api_key
func _ready():
# Create HTTPRequest node
http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(_on_request_completed)
func submit_form(submission_data: Dictionary) -> void:
var url = BASE_URL + "/submit"
var headers = [
"Content-Type: application/json",
"X-API-Key: " + api_key
]
var json_data = JSON.stringify(submission_data)
var error = http_request.request(url, headers, HTTPClient.METHOD_POST, json_data)
if error != OK:
push_error("Failed to send HTTP request: " + str(error))
submission_completed.emit(false, "Failed to send request")
func _on_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
var json = JSON.new()
var parse_result = json.parse(body.get_string_from_utf8())
if parse_result != OK:
push_error("Failed to parse JSON response")
submission_completed.emit(false, "Failed to parse response")
return
var response = json.get_data()
if response_code == 200 or response_code == 201:
print("Submission successful: ", response.message)
submission_completed.emit(true, response.message)
else:
push_error("Submission failed: " + response.message)
submission_completed.emit(false, response.message)
# Helper function to create a field
static func create_field(key: String, label: String, type: String, value, options = null) -> Dictionary:
var field = {
"key": key,
"label": label,
"type": type,
"value": value
}
if options != null:
field["options"] = options
return field
Godot 3.x Users: The syntax is slightly different in Godot 3. Replace request_completed.connect() with connect("request_completed", ...) and use PoolByteArray instead of PackedByteArray.
Step 2: Create a Feedback UI Scene
Create a new scene with a feedback form. Here's the script for the feedback scene:
extends Control
# Reference to UI elements (assign in the editor)
@onready var rating_slider = $VBoxContainer/RatingSlider
@onready var comments_text = $VBoxContainer/CommentsTextEdit
@onready var difficulty_option = $VBoxContainer/DifficultyOptionButton
@onready var submit_button = $VBoxContainer/SubmitButton
@onready var status_label = $VBoxContainer/StatusLabel
var indieop_client: IndieOpClient
func _ready():
# Initialize the client
indieop_client = IndieOpClient.new("your_game_api_key_here")
add_child(indieop_client)
# Connect signals
submit_button.pressed.connect(_on_submit_pressed)
indieop_client.submission_completed.connect(_on_submission_completed)
# Setup difficulty options
difficulty_option.clear()
difficulty_option.add_item("Easy")
difficulty_option.add_item("Medium")
difficulty_option.add_item("Hard")
difficulty_option.select(1) # Default to Medium
func _on_submit_pressed():
submit_button.disabled = true
status_label.text = "Submitting..."
var rating = int(rating_slider.value)
var comments = comments_text.text
var difficulty = difficulty_option.get_item_text(difficulty_option.selected)
var submission = {
"form_name": "Player Feedback",
"tag": "feedback",
"form_type": "feedback",
"player_identifier": OS.get_unique_id(),
"game_version": ProjectSettings.get_setting("application/config/version"),
"fields": [
IndieOpClient.create_field("rating", "Overall Rating", "rating", rating),
IndieOpClient.create_field("comments", "Your Feedback", "text", comments),
IndieOpClient.create_field("difficulty", "Difficulty Level", "dropdown", difficulty,
["Easy", "Medium", "Hard"]),
IndieOpClient.create_field("enjoyed", "Did you enjoy?", "checkbox", true)
]
}
indieop_client.submit_form(submission)
func _on_submission_completed(success: bool, message: String):
submit_button.disabled = false
if success:
status_label.text = "Thank you for your feedback!"
status_label.add_theme_color_override("font_color", Color.GREEN)
# Clear form
comments_text.text = ""
rating_slider.value = 5
else:
status_label.text = "Failed to submit: " + message
status_label.add_theme_color_override("font_color", Color.RED)
Step 3: Create the UI Layout
In the Godot editor, create this node structure for your feedback scene:
Control (FeedbackScene)
└── VBoxContainer
├── Label (title)
├── HBoxContainer
│ ├── Label ("Rating:")
│ └── HSlider (RatingSlider) - min: 1, max: 5
├── Label ("Difficulty:")
├── OptionButton (DifficultyOptionButton)
├── Label ("Comments:")
├── TextEdit (CommentsTextEdit)
├── Button (SubmitButton)
└── Label (StatusLabel)
Bug Report Example
Here's how to create a simple bug report system:
extends Node
var indieop_client: IndieOpClient
func _ready():
indieop_client = IndieOpClient.new("your_game_api_key_here")
add_child(indieop_client)
func submit_bug_report(description: String, severity: String):
var submission = {
"form_name": "Bug Report",
"tag": "bugs",
"form_type": "bug_report",
"player_identifier": OS.get_unique_id(),
"game_version": ProjectSettings.get_setting("application/config/version"),
"repository_version": "main@abc123",
"fields": [
IndieOpClient.create_field("description", "Bug Description", "text", description),
IndieOpClient.create_field("severity", "Severity", "dropdown", severity,
["Low", "Medium", "High", "Critical"]),
IndieOpClient.create_field("reproducible", "Can Reproduce?", "checkbox", true)
]
}
indieop_client.submit_form(submission)
indieop_client.submission_completed.connect(_on_bug_report_submitted)
func _on_bug_report_submitted(success: bool, message: String):
if success:
print("Bug report submitted successfully")
else:
print("Failed to submit bug report: ", message)
# Example: Call this when player encounters a bug
func _unhandled_input(event):
if event.is_action_pressed("report_bug"): # Add this input action in Project Settings
submit_bug_report("Player fell through floor in Level 3", "High")
Autoload Setup (Recommended)
For easier access throughout your game, set up the IndieOp client as an autoload:
-
Create a global script called
indieop_global.gd:extends Node var client: IndieOpClient func _ready(): client = IndieOpClient.new("your_game_api_key_here") add_child(client) func submit_feedback(rating: int, comments: String): var submission = { "form_name": "Player Feedback", "tag": "feedback", "form_type": "feedback", "player_identifier": OS.get_unique_id(), "game_version": ProjectSettings.get_setting("application/config/version"), "fields": [ IndieOpClient.create_field("rating", "Overall Rating", "rating", rating), IndieOpClient.create_field("comments", "Comments", "text", comments) ] } client.submit_form(submission) -
Add to autoload: Go to Project → Project Settings → Autoload, and add
indieop_global.gdwith the name "IndieOp" -
Use anywhere in your game:
# Can now access from any script IndieOp.submit_feedback(5, "Amazing game!")
Field Types Reference
The Indieop API supports four field types:
| Field Type | GDScript Type | Example |
|---|---|---|
| text | String | "Great game!" |
| rating | int (1-5) | 5 |
| checkbox | bool | true |
| dropdown | String (from Array) | "Medium" |
Error Handling
Implement retry logic and offline queueing:
extends Node
var failed_submissions: Array = []
var retry_timer: Timer
func _ready():
# Setup retry timer
retry_timer = Timer.new()
add_child(retry_timer)
retry_timer.wait_time = 60.0 # Retry every minute
retry_timer.timeout.connect(_retry_failed_submissions)
retry_timer.start()
func store_failed_submission(submission_data: Dictionary):
failed_submissions.append({
"data": submission_data,
"timestamp": Time.get_unix_time_from_system()
})
print("Submission stored for retry. Queue size: ", failed_submissions.size())
func _retry_failed_submissions():
if failed_submissions.is_empty():
return
print("Retrying ", failed_submissions.size(), " failed submissions...")
var remaining = []
for item in failed_submissions:
# Try to resubmit
var client = get_node("IndieOpClient") # Or use autoload
client.submit_form(item.data)
# Check if successful via signal
# If not, keep in queue
remaining.append(item)
failed_submissions = remaining
Best Practices
- Use autoload for global access: Makes the client available throughout your game
- Store API key in environment: Use Godot's feature tags or external config files
- Handle offline scenarios: Queue submissions when network is unavailable
- Validate before sending: Check field values match expected types
- Rate limiting: Don't exceed 100 requests per minute
- Free HTTPRequest nodes: Call
queue_free()when done if creating many