Home Docs JavaScript

JavaScript Quick Start

Integrate Indieop API into your JavaScript games for web and Node.js.

Prerequisites

Before you begin, make sure you have:

  1. Created an Indieop account
  2. 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

Next Steps