JavaScript Quick Start
Integrate Indieop API into your JavaScript games for web and Node.js.
Prerequisites
Before you begin, make sure you have:
- Created an Indieop account
- Created a game and obtained your API key from the game settings
Overview
This guide shows you how to send player feedback and form submissions from your JavaScript game to the Indieop API. Works with:
- Browser games: Phaser, Three.js, PixiJS, vanilla JavaScript
- Node.js games: Server-side game logic
Browser Implementation
Step 1: Create the API Client
Create a new JavaScript file called indieop-client.js:
class IndieOpClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://indieop.com/api/sdk';
}
async submitForm(submissionData) {
try {
const response = await fetch(`${this.baseURL}/submit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
},
body: JSON.stringify(submissionData)
});
const data = await response.json();
if (response.ok) {
console.log('Submission successful:', data);
return { success: true, data };
} else {
console.error('Submission failed:', data);
return { success: false, error: data.message };
}
} catch (error) {
console.error('Network error:', error);
return { success: false, error: error.message };
}
}
// Helper method to create a properly formatted field
createField(key, label, type, value, options = null) {
const field = { key, label, type, value };
if (options) field.options = options;
return field;
}
}
Step 2: Use the Client in Your Game
Here's an example of submitting player feedback:
// Initialize the client
const client = new IndieOpClient('your_game_api_key_here');
// Submit player feedback
async function submitPlayerFeedback(rating, comments, difficulty) {
const submission = {
form_name: 'Player Feedback',
tag: 'feedback',
form_type: 'feedback',
player_identifier: localStorage.getItem('playerId') || 'anonymous',
game_version: '1.0.0',
fields: [
client.createField('rating', 'Overall Rating', 'rating', rating),
client.createField('comments', 'Your Feedback', 'text', comments),
client.createField('difficulty', 'Difficulty Level', 'dropdown', difficulty,
['Easy', 'Medium', 'Hard']),
client.createField('enjoyed', 'Did you enjoy?', 'checkbox', true)
]
};
const result = await client.submitForm(submission);
if (result.success) {
alert('Thank you for your feedback!');
} else {
alert('Failed to submit feedback. Please try again.');
}
}
// Example: Submit feedback when player clicks a button
document.getElementById('submitFeedback').addEventListener('click', async () => {
const rating = parseInt(document.getElementById('rating').value);
const comments = document.getElementById('comments').value;
const difficulty = document.getElementById('difficulty').value;
await submitPlayerFeedback(rating, comments, difficulty);
});
Step 3: HTML Form Example
Here's a simple HTML form to collect feedback:
<div class="feedback-form">
<h2>How was your experience?</h2>
<label>
Rating (1-5):
<input type="number" id="rating" min="1" max="5" value="5">
</label>
<label>
Difficulty:
<select id="difficulty">
<option value="Easy">Easy</option>
<option value="Medium" selected>Medium</option>
<option value="Hard">Hard</option>
</select>
</label>
<label>
Comments:
<textarea id="comments" rows="4"></textarea>
</label>
<button id="submitFeedback">Submit Feedback</button>
</div>
<script src="indieop-client.js"></script>
<script src="game.js"></script>
Node.js Implementation
For server-side games or Node.js applications:
// indieop-client.js (Node.js version)
const https = require('https');
class IndieOpClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://indieop.com/api/sdk';
}
submitForm(submissionData) {
return new Promise((resolve, reject) => {
const data = JSON.stringify(submissionData);
const options = {
hostname: 'indieop.com',
path: '/api/sdk/submit',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
'X-API-Key': this.apiKey
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
try {
const parsed = JSON.parse(responseData);
if (res.statusCode === 200 || res.statusCode === 201) {
resolve({ success: true, data: parsed });
} else {
resolve({ success: false, error: parsed.message });
}
} catch (error) {
reject(error);
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(data);
req.end();
});
}
}
module.exports = IndieOpClient;
// Usage example
const IndieOpClient = require('./indieop-client');
const client = new IndieOpClient('your_game_api_key_here');
async function submitBugReport(description, playerName) {
const submission = {
form_name: 'Bug Report',
tag: 'bugs',
form_type: 'bug_report',
player_identifier: playerName,
game_version: process.env.GAME_VERSION || '1.0.0',
fields: [
{
key: 'bug_description',
label: 'Bug Description',
type: 'text',
value: description
},
{
key: 'severity',
label: 'Severity',
type: 'dropdown',
options: ['Low', 'Medium', 'High', 'Critical'],
value: 'Medium'
}
]
};
try {
const result = await client.submitForm(submission);
if (result.success) {
console.log('Bug report submitted successfully');
}
} catch (error) {
console.error('Failed to submit bug report:', error);
}
}
submitBugReport('Player falls through floor in level 3', 'player123');
Phaser.js Integration Example
If you're using Phaser, here's how to integrate feedback collection:
class GameOverScene extends Phaser.Scene {
constructor() {
super('GameOverScene');
this.client = new IndieOpClient('your_game_api_key_here');
}
create(data) {
// Show game over screen
this.add.text(400, 300, 'Game Over!', { fontSize: '48px' });
// Show rating prompt
this.add.text(400, 400, 'How would you rate this session?', { fontSize: '24px' });
// Create rating buttons
for (let i = 1; i <= 5; i++) {
const button = this.add.text(300 + (i * 40), 450, i.toString(), {
fontSize: '32px',
backgroundColor: '#4F46E5',
padding: { x: 10, y: 5 }
})
.setInteractive()
.on('pointerdown', () => this.submitRating(i, data.score));
}
}
async submitRating(rating, score) {
const submission = {
form_name: 'Game Session Feedback',
tag: 'session_feedback',
form_type: 'feedback',
game_version: '1.0.0',
fields: [
{
key: 'rating',
label: 'Session Rating',
type: 'rating',
value: rating
},
{
key: 'final_score',
label: 'Final Score',
type: 'text',
value: score.toString()
}
]
};
const result = await this.client.submitForm(submission);
if (result.success) {
this.add.text(400, 500, 'Thanks for your feedback!', {
fontSize: '20px',
color: '#10B981'
});
}
}
}
Error Handling
Always implement proper error handling:
async function submitWithRetry(submissionData, maxRetries = 3) {
const client = new IndieOpClient('your_game_api_key_here');
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await client.submitForm(submissionData);
if (result.success) {
return result;
}
// If not successful, log and retry
console.log(`Attempt ${attempt} failed: ${result.error}`);
if (attempt < maxRetries) {
// Wait before retrying (exponential backoff)
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
} catch (error) {
console.error(`Network error on attempt ${attempt}:`, error);
if (attempt === maxRetries) {
// Store locally for later submission
storeFailedSubmission(submissionData);
return { success: false, error: 'Max retries exceeded' };
}
}
}
}
function storeFailedSubmission(data) {
const stored = JSON.parse(localStorage.getItem('failedSubmissions') || '[]');
stored.push({ data, timestamp: Date.now() });
localStorage.setItem('failedSubmissions', JSON.stringify(stored));
console.log('Submission stored locally for later');
}
// Retry failed submissions when connection is restored
async function retryFailedSubmissions() {
const stored = JSON.parse(localStorage.getItem('failedSubmissions') || '[]');
if (stored.length === 0) return;
const client = new IndieOpClient('your_game_api_key_here');
const remaining = [];
for (const item of stored) {
const result = await client.submitForm(item.data);
if (!result.success) {
remaining.push(item);
}
}
localStorage.setItem('failedSubmissions', JSON.stringify(remaining));
console.log(`Retried ${stored.length - remaining.length} failed submissions`);
}
// Check for failed submissions periodically
setInterval(retryFailedSubmissions, 60000); // Every minute
Best Practices
- Never expose your API key in public repositories - Use environment variables
- Implement offline support: Queue submissions locally if network is unavailable
- Validate data before sending: Check field values match their types
- Rate limiting: Don't exceed 100 requests per minute
- User privacy: Only collect necessary data and inform players