Getting Started

Gamify Everything provides a set of API endpoints to easily integrate gamification features into your app. It handles user tracking, calculation and data storage for you and allows you to write some frontend code to visualize your users' progress the way that works for you, your product and your brand.

To get started, create an account and add a subscription. Then create an app and select it.

From the app section you can create an API key that you need to use with every call to the API.

In the following we'll have a look at how the API works with some JavaScript examples. Feel free to adapt the code if your application uses a different language.

To make each API call a bit less verbose, let's define a post function that includes boilerplate parameters and the API key.

const rootUrl = "https://gamifyeverything.com"
  const apiKey = "your-api-key"
  const app = "your-app-identifier"
  const headers = new Headers()
  headers.set("Content-Type", "application/json")

  const post = async (url, body) => {
    body.api_key = apiKey
    body.app = app
    const response = await fetch(`${rootUrl}/api${url}`, {
      method: "POST",
      mode: "cors",
      cache: "no-cache",
      credentials: "same-origin",
      headers: headers,
      redirect: "follow",
      referrerPolicy: "no-referrer",
      body: JSON.stringify(body),
    })
    returnValue = await response.json()
    return returnValue
  }

Now we can write some API calls!

Streaks

The streak feature lets you motivate your users to keep using your app by building a habit.

After you sign in select your app. From the app section you can manage the streak feature. You can create an arbitrary number of streaks for your app, with different cycle lengths. E.g. with a 1-day cycle lengths your users need to check in once a day to keep their streak going.

Let's look at a code example:

// Create a check in for your app's user
  let response = await post(`/check_ins/create`, { 
    check_in: { 
      // Pass a user identifier that is unique within your app.
      // This can be a username, an id or something else as long as it's a unique identifier.
      // With this identifier you can later update and fetch all info for this user.
      identifier: "streakUser2000" 
    } 
  })

  /* Response:

  { "data": {
    "inserted_at": "2023-10-10T09:59:41"
  }}
  */

  // Get the streak info
  response = await post(`/streak_status`, { 
    streak: { 
      identifier: "streakUser2000"
    } 
  })
  
  /* The response is a list of statuses for all the streaks you have defined

  { "data": [
    {
      "has_checked_in": true,                 // true if user has checked in in current cycle
      "streak_length": 1,                     // number of completed cycles
      "cycle_duration_days": 1,               // cycle length in days
      "cycle_start": "2023-10-10T00:00:00"    // start timestamp of the first cycle of this streak
    }
  ]}
  */

Here's a minimal code example of how you can put together a Streak UI:

const root = document.querySelector("#streak")
  root.style = "width: 150px; height: 150px; box-shadow: 5px 5px 30px -18px rgba(0,0,0,1); font-size: 2em; font-family: sans-serif; border-radius: 1em; display: flex; flex-direction: column; justify-content: center; text-align: center; margin: 1em;"
  
  const flame = document.createElement("span")
  flame.innerText = "🔥"
  flame.style.filter = `grayscale(${response.data[0].has_checked_in ? "0" : "100"}%)`
  
  const text = document.createElement("span")
  text.innerText = `${response.data[0].streak_length} Days!`
  
  root.appendChild(flame)
  root.appendChild(text)

Punch Card

With the punch card you can show your users' activity over time.

To get the necessary data, just specify the start and end date and the API will deliver check in data in this time period.

const now = Date.now()
  const ninetyDaysBefore = now - 1000 * 60 * 60 * 24 * 90
  const nowString = new Date(now).toISOString()
  const ninetyDaysBeforeString = new Date(ninetyDaysBefore).toISOString()
  
  // Get the user's check ins within the specified time range
  let response = await post(`/check_ins`, {
    check_ins: { 
      identifier: "streakUser2000", 
      start: ninetyDaysBeforeString, 
      end: nowString, 
      streak: "your-streak-id"
    }
  })
  
  /* The response is a list of cycles for the streak and the
    specified time range with the number of check ins each.
    Date.parse() let's you parse the timestamps.

  { "data": [
    {
      "cycle_start": "2023-07-12T00:00:00.000000Z",
      "cycle_end": "2023-07-13T00:00:00.000000Z",
      "check_ins_count": 3
    },
    {
      "cycle_start": "2023-07-13T00:00:00.000000Z",
      "cycle_end": "2023-07-14T00:00:00.000000Z",
      "check_ins_count": 0
    },
    {
      "cycle_start": "2023-07-14T00:00:00.000000Z",
      "cycle_end": "2023-07-15T00:00:00.000000Z",
      "check_ins_count": 1
    },
    // ...
  ]}
  */

Here's a minimal code example of how you can put together a Punch Card UI for daily check ins, similar to the one on GitHub Profiles:

const root = document.querySelector("#punch-card")
  const weeks = [[]]

  let highestCount = 0
  response.data.forEach(({ check_ins_count }) => {
    highestCount = check_ins_count > highestCount ? check_ins_count : highestCount
  })

  response.data.forEach(checkIn => {
    let currentWeek = weeks[weeks.length - 1]
    if (currentWeek.length >= 7) {
      weeks.push([])
      currentWeek = weeks[weeks.length - 1]
    }
    currentWeek.push(checkIn)
  })
  root.style = "display: inline-flex; flex-direction: row; box-shadow: 5px 5px 30px -18px rgba(0,0,0,1); margin: 1em; padding: 1em; border-radius: 1em;"
  weeks.forEach(week => {
    const weekEl = document.createElement("div")
    weekEl.style="display: flex; flex-direction: column;"
    root.appendChild(weekEl)
    week.forEach(checkIn => {
      const dayEl = document.createElement("div")
      dayEl.style = `width: 10px; height: 10px; margin: 2px; background-color: blue; border-radius: 3px; opacity: ${checkIn.check_ins_count / highestCount * 0.9 + 0.1};`
      const date = new Date(Date.parse(checkIn.cycle_start))
      dayEl.title = `${date.getDate()}.${date.getMonth()}.${date.getFullYear()} - ${checkIn.check_ins_count}`
      weekEl.appendChild(dayEl)
    })
  })

XP and Levels

After completing tasks in your app you can reward your users with experience points. If a user has collected enough XP the user's level progresses. Reaching a new level becomes progressively more difficult. The API delivers all the data needed.

You could use the levels to unlock features in your app for your users as they progress.

// Add XP to the user
  let response = await post(`/app_user/add_xp`, { 
    app_user: { 
      identifier: "streakUser2000", 
      xp: 200 
    } 
  })
  
  // Query XP and Level stats of the user
  response = await post(`/app_user`, { 
    app_user: { 
      identifier: "streakUser2000" 
    } 
  })
  
  /* Response:

  { "data": {
    "identifier": "streakUser2000",
    "level": 1,                       // User's current level
    "xp": 200,                        // User's total XP 
    "level_start": 0,                 // Total XP needed to start the current level
    "level_end": 204,                 // Total XP needed to complete the current level
    "level_size": 204,                // XP between level_start and level_end
    "level_progress": 200,            // Progress of current level in XP
    "level_progress_percent": 98,     // Progress of current level in percent
    "level_remaining": 4,             // Remaining XP to comlete the current level
    //...
  }}
  */

Here's a minimal code example of how you can put together a Level UI:

const root = document.querySelector("#xp-bar")
  root.style = "width: 200px; font-family: sans-serif; text-align: center; box-shadow: 5px 5px 30px -18px rgba(0,0,0,1); border-radius: 1em; margin: 1em; padding: 1em;"
  removeAllChildNodes(root)

  const levelText = document.createElement("p")
  levelText.innerText = `Level ${response.data.level}`
  levelText.style = "font-size: 2em;"

  const remainingText = document.createElement("p")
  remainingText.innerText = `${response.data.level_remaining} until Level ${response.data.level + 1}`

  const progress = document.createElement("progress")
  progress.innerText = `${response.data.level_progress_percent}%`
  progress.value = response.data.level_progress_percent
  progress.max = 100
  progress.style = "width: 100%;"

  const barAnnotation = document.createElement("div")
  barAnnotation.style = "display: flex; flex-direction: row; justify-content: space-between;"

  const barStart = document.createElement("span")
  barStart.innerText = 0

  const barEnd = document.createElement("span")
  barEnd.innerText = response.data.level_size

  const barProgress = document.createElement("span")
  barProgress.innerText = `${response.data.level_progress} (${response.data.level_progress_percent}%)`

  barAnnotation.appendChild(barStart)
  barAnnotation.appendChild(barProgress)
  barAnnotation.appendChild(barEnd)

  root.appendChild(levelText)
  root.appendChild(progress)
  root.appendChild(barAnnotation)
  root.appendChild(remainingText)

In-App Currency

Another way to reward your users is through in-app currency.

The API provides functions to add and subtract coins from the user's balance. You could even build a whole in-app store system on top of this.

// Add coins to the user
  let response = await post(`/app_user/add_coins`, { 
    app_user: { 
      identifier: "streakUser2000", 
      coins: 200 
    } 
  })

  // Subtract coins from the user
  response = await post(`/app_user/subtract_coins`, { 
    app_user: { 
      identifier: "streakUser2000", 
      coins: 50
    } 
  })
  
  // Query the user's balance
  response = await post(`/app_user`, { 
    app_user: { 
      identifier: "streakUser2000" 
    } 
  })
  
  /* Response:
  
  { "data": {
    "identifier": "streakUser2000",
    "coins": 200,
    //...
  }}
  */

Here's a minimal code example of how you can put together a UI for In-App Currency:

const root = document.querySelector("#coins")
  root.style = "width: 150px; height: 150px; box-shadow: 5px 5px 30px -18px rgba(0,0,0,1); font-size: 2em; font-family: sans-serif; border-radius: 1em; display: flex; flex-direction: column; justify-content: center; text-align: center; margin: 1em;"
  
  const text = document.createElement("span")
  text.innerText = `🪙${response.data.coins}`
  
  root.appendChild(text)

Happy gamifying!