> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scanova.io/llms.txt
> Use this file to discover all available pages before exploring further.

# QR Code Analytics

> Retrieve in-depth QR Code performance analytics including scan counts, devices, operating systems, browsers, geographic insights, and time-based metrics. Supports filtering, grouping, and multiple analytic types in a single request. Authentication required.

## Description

This endpoint provides **comprehensive analytics** for one or more QR codes in your account.\
You can query by:

* **QR IDs** (specific QR codes), or
* **Tags** (group of QR codes with the same tag).

It supports a variety of **analytics types** — such as scans by date, device, browser, geography, and more — allowing you to build dashboards and reports programmatically.

## Query Parameters

| Parameter          | Type                  | Required | Description                                                                                                                                       |
| :----------------- | :-------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`             | `string`              | No       | Comma-separated list of analytics types to include in the response. Defaults to all.                                                              |
| `from`             | `string (YYYY-MM-DD)` | Yes      | Start date for analytics data (inclusive).                                                                                                        |
| `to`               | `string (YYYY-MM-DD)` | Yes      | End date for analytics data (inclusive). Defaults to current date.                                                                                |
| `exclude_bot_scan` | `boolean`             | No       | When `true`, bot scans are excluded from all aggregations and returned separately under the `bot_scans` key in the response. Defaults to `false`. |

### Supported `type` Values

| Type           | Description                                       |
| :------------- | :------------------------------------------------ |
| `count`        | Scan count overview (total, unique, trends)       |
| `qr`           | QR code-level summary                             |
| `device`       | Breakdown by device type (e.g., Mobile, PC)       |
| `os`           | Breakdown by operating system                     |
| `browser`      | Breakdown by browser type                         |
| `date`         | Time-series data by date                          |
| `handset`      | Breakdown by handset or device model              |
| `geography`    | Country/region-level distribution                 |
| `geo_location` | Detailed city-level location data                 |
| `day_time`     | Hourly and day-based scan distribution            |
| `age`          | Age group data (if enabled in analytics settings) |

## Request Body

| Field       | Type     | Required | Description                                                   |
| :---------- | :------- | :------- | :------------------------------------------------------------ |
| `filter_by` | `string` | Yes      | Specify filter type — either `qrid` or `tags` or `folder`.    |
| `q`         | `array`  | Yes      | List of QR IDs or tags or folder ids to filter analytics for. |

## Examples

### **Get QR Code Analytics by QR ID**

```bash theme={null}
curl -X POST "https://management.scanova.io/analytics/qr/?from=2025-02-01&to=2025-02-25&type=count,device,os" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter_by": "qrid",
    "q": ["Qf94b25d768294148"]
  }'
```

### **Get Analytics by Tags**

```bash theme={null}
curl -X POST "https://management.scanova.io/analytics/qr/?from=2025-02-01&to=2025-02-25&type=count,geography" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter_by": "tags",
    "q": ["marketing", "campaign"]
  }'
```

### **Get Multiple QR Codes Analytics**

```bash theme={null}
curl -X POST "https://management.scanova.io/analytics/qr/?from=2025-01-01&to=2025-01-31&type=count,device,os,browser,date" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter_by": "qrid",
    "q": ["Qf94b25d768294148", "Qf94b25d768294149", "Qf94b25d768294150"]
  }'
```

### **Get All Analytics Types**

```bash theme={null}
curl -X POST "https://management.scanova.io/analytics/qr/?from=2025-02-01&to=2025-02-25&type=count,qr,device,os,browser,date,handset,geography,geo_location" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter_by": "qrid",
    "q": ["Qf94b25d768294148"]
  }'
```

### **Exclude Bot Scans**

```bash theme={null}
curl -X POST "https://management.scanova.io/analytics/qr/?from=2025-02-01&to=2025-02-25&type=count,device&exclude_bot_scan=true" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter_by": "qrid",
    "q": ["Qf94b25d768294148"]
  }'
```

## Response Structure

### **Success Response (200 OK)**

The response structure varies based on the `type` query parameter. Response keys depend on the requested analytics types.

#### **Complete Analytics Response (all types requested)**

```json theme={null}
{
  "qr": [
    ["QR Code", 1]
  ],
  "count": {
    "total": 1,
    "elevation": {
      "percent": 100,
      "previous": 2,
      "type": "-",
      "period": {
        "start": "2025-10-11T18:07:00Z",
        "end": "2025-10-18T18:07:00Z"
      }
    },
    "unique": 1,
    "unique_elevation": {
      "percent": 100,
      "previous": 2,
      "type": "-",
      "period": {
        "start": "2025-10-11T18:07:00Z",
        "end": "2025-10-18T18:07:00Z"
      }
    },
    "scan_qr": 0,
    "scan_url": 1
  },
  "device": [
    ["PC", 1]
  ],
  "os": [
    ["Mac OS X", 1]
  ],
  "date": {
    "all": [
      ["2025-10-18", 0],
      ["2025-10-19", 0],
      ["2025-10-20", 0],
      ["2025-10-21", 0],
      ["2025-10-22", 0],
      ["2025-10-23", 0],
      ["2025-10-24", 0],
      ["2025-10-25", 1],
      ["2025-10-26", 0]
    ],
    "qr": [
      ["2025-10-18", 0],
      ["2025-10-19", 0],
      ["2025-10-20", 0],
      ["2025-10-21", 0],
      ["2025-10-22", 0],
      ["2025-10-23", 0],
      ["2025-10-24", 0],
      ["2025-10-25", 0],
      ["2025-10-26", 0]
    ],
    "url": [
      ["2025-10-18", 0],
      ["2025-10-19", 0],
      ["2025-10-20", 0],
      ["2025-10-21", 0],
      ["2025-10-22", 0],
      ["2025-10-23", 0],
      ["2025-10-24", 0],
      ["2025-10-25", 1],
      ["2025-10-26", 0]
    ]
  },
  "handset": [
    ["Mac", 1]
  ],
  "browser": [
    ["Chrome", 1]
  ],
  "geography": [
    {
      "country_code": "Unknown",
      "country_name": "Unknown",
      "region": "Unknown",
      "city": "Unknown",
      "count": 1
    }
  ],
  "geo_location": [],
  "age": [],
  "day_time": [
    ["Sun", "00", 0],
    ["Sun", "01", 1],
    ["Sun", "02", 0],
    ["Mon", "09", 2],
    ["Mon", "14", 3],
    ["Tue", "18", 1],
    ["Wed", "12", 2],
    ["Thu", "16", 1],
    ["Fri", "11", 2],
    ["Sat", "20", 1]
  ]
}
```

#### **Count Analytics Only**

```json theme={null}
{
  "count": {
    "total": 1,
    "elevation": {
      "percent": 100,
      "previous": 2,
      "type": "-",
      "period": {
        "start": "2025-10-11T18:07:00Z",
        "end": "2025-10-18T18:07:00Z"
      }
    },
    "unique": 1,
    "unique_elevation": {
      "percent": 100,
      "previous": 2,
      "type": "-",
      "period": {
        "start": "2025-10-11T18:07:00Z",
        "end": "2025-10-18T18:07:00Z"
      }
    },
    "scan_qr": 0,
    "scan_url": 1
  }
}
```

#### **Device, OS, and Browser Analytics**

```json theme={null}
{
  "device": [
    ["PC", 1]
  ],
  "os": [
    ["Mac OS X", 1]
  ],
  "browser": [
    ["Chrome", 1]
  ]
}
```

#### **Analytics with Bot Scans Excluded (`exclude_bot_scan=true`)**

When `exclude_bot_scan=true` is passed, all aggregations reflect human traffic only and the response includes a `bot_scans` summary:

```json theme={null}
{
  "count": {
    "total": 85,
    "unique": 72
  },
  "device": [
    ["Mobile", 60],
    ["PC", 25]
  ],
  "bot_scans": {
    "total": 12,
    "unique": 5,
    "by_type": [
      ["Googlebot", 7],
      ["AhrefsBot", 5]
    ],
    "by_qr": [
      ["My Campaign QR", 10],
      ["Landing Page QR", 2]
    ]
  }
}
```

## Response Schema

Each analytics type returns a separate structure.

| Key            | Description                                                               | Example Format                                                 |
| :------------- | :------------------------------------------------------------------------ | :------------------------------------------------------------- |
| `count`        | Summary metrics for scans                                                 | `{ "total": 150, "unique": 120 }`                              |
| `device`       | Device type counts                                                        | `[["Mobile", 100], ["Desktop", 50]]`                           |
| `os`           | Operating systems                                                         | `[["Android", 80], ["iOS", 40]]`                               |
| `browser`      | Browser breakdown                                                         | `[["Chrome", 60], ["Safari", 30]]`                             |
| `date`         | Daily scan counts                                                         | `{ "all": [["2025-10-25", 5], ["2025-10-26", 2]] }`            |
| `geography`    | Country/region breakdown                                                  | `[{"country_name": "India", "count": 30}]`                     |
| `geo_location` | City-level data                                                           | `[{"city": "Delhi", "count": 10}]`                             |
| `day_time`     | Hourly scan distribution                                                  | `[["Mon", "09", 2], ["Tue", "14", 1]]`                         |
| `bot_scans`    | Bot scan summary — only present when `exclude_bot_scan=true` is requested | `{"total": 12, "unique": 5, "by_type": [...], "by_qr": [...]}` |

## Use Cases

* 📈 Build custom **QR code analytics dashboards**
* 🗺️ Analyze **user scan geography and device trends**
* ⏰ Study **time-based scan activity**
* 🧭 Track **campaign performance** by tags or QR IDs
* 🧮 Export **scan data summaries** for internal BI systems

## Integration Examples

### **JavaScript - Get QR Code Analytics**

```javascript theme={null}
async function getQRAnalytics(filterBy, q, fromDate, toDate, types = 'count,device,os') {
  try {
    const response = await fetch(
      `https://management.scanova.io/analytics/qr/?from=${fromDate}&to=${toDate}&type=${types}`,
      {
        method: 'POST',
        headers: {
          'Authorization': 'YOUR_API_KEY',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          filter_by: filterBy,
          q: q
        })
      }
    );
    
    if (response.ok) {
      const analytics = await response.json();
      return analytics;
    } else {
      throw new Error('Failed to fetch analytics');
    }
  } catch (error) {
    console.error('Error fetching analytics:', error);
    return null;
  }
}

// Usage - Get analytics by QR ID
const analytics = await getQRAnalytics('qrid', ['Qf94b25d768294148'], '2025-02-01', '2025-02-25');
console.log('Analytics data:', analytics);

// Usage - Get analytics by tags
const tagAnalytics = await getQRAnalytics('tags', ['marketing', 'campaign'], '2025-02-01', '2025-02-25', 'count,geography');

// Usage - Get multiple QR codes analytics
const multiAnalytics = await getQRAnalytics('qrid', ['Qf94b25d768294148', 'Qf94b25d768294149'], '2025-02-01', '2025-02-25', 'count,device,os,browser');
```

### **Python - Get QR Code Analytics**

```python theme={null}
import requests
from datetime import datetime, timedelta

def get_qr_analytics(filter_by, q, from_date, to_date, types='count,device,os'):
    url = "https://management.scanova.io/analytics/qr/"
    headers = {
        "Authorization": "YOUR_API_KEY",
        "Content-Type": "application/json"
    }
    
    params = {
        'from': from_date,
        'to': to_date,
        'type': types
    }
    
    data = {
        'filter_by': filter_by,
        'q': q
    }
    
    try:
        response = requests.post(url, headers=headers, params=params, json=data)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error fetching analytics: {e}")
        return None

def analyze_qr_performance(qr_ids, days=30, types='count,device,os,geography'):
    """Get analytics for the last N days"""
    to_date = datetime.now().strftime('%Y-%m-%d')
    from_date = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d')
    
    analytics = get_qr_analytics('qrid', qr_ids, from_date, to_date, types)
    if analytics:
        print(f"Analytics for QR Codes: {qr_ids}")
        print(f"Date Range: {from_date} to {to_date}")
        
        # Display analytics based on requested types
        if 'count' in types:
            print(f"\nScan Counts: {analytics.get('count', 'N/A')}")
        
        if 'device' in types:
            print(f"\nDevice Analytics: {analytics.get('device', 'N/A')}")
        
        if 'geography' in types:
            print(f"\nGeographic Analytics: {analytics.get('geography', 'N/A')}")
    
    return analytics

def get_analytics_by_tags(tags, from_date, to_date, types='count,geography'):
    """Get analytics for QR codes with specific tags"""
    return get_qr_analytics('tags', tags, from_date, to_date, types)

# Usage - Get analytics by QR ID
analytics = get_qr_analytics('qrid', ['Qf94b25d768294148'], '2025-02-01', '2025-02-25')
print("Analytics:", analytics)

# Usage - Get analytics by tags
tag_analytics = get_analytics_by_tags(['marketing', 'campaign'], '2025-02-01', '2025-02-25')

# Usage - Analyze performance for multiple QR codes
analyze_qr_performance(['Qf94b25d768294148', 'Qf94b25d768294149'], 30, 'count,device,os,browser,geography')
```

### **PHP - Get QR Code Analytics**

```php theme={null}
<?php
function getQRAnalytics($filterBy, $q, $fromDate, $toDate, $types = 'count,device,os') {
    $url = "https://management.scanova.io/analytics/qr/";
    $headers = [
        "Authorization: YOUR_API_KEY",
        "Content-Type: application/json"
    ];
    
    $params = http_build_query([
        'from' => $fromDate,
        'to' => $toDate,
        'type' => $types
    ]);
    
    $data = json_encode([
        'filter_by' => $filterBy,
        'q' => $q
    ]);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200) {
        return json_decode($response, true);
    } else {
        echo "Error fetching analytics: " . $response;
        return null;
    }
}

function analyzeQRPerformance($qrIds, $days = 30, $types = 'count,device,os,geography') {
    $toDate = date('Y-m-d');
    $fromDate = date('Y-m-d', strtotime("-{$days} days"));
    
    $analytics = getQRAnalytics('qrid', $qrIds, $fromDate, $toDate, $types);
    if ($analytics) {
        echo "Analytics for QR Codes: " . implode(', ', $qrIds) . "\n";
        echo "Date Range: {$fromDate} to {$toDate}\n";
        
        // Display analytics based on requested types
        if (strpos($types, 'count') !== false) {
            echo "\nScan Counts: " . json_encode($analytics['count'] ?? 'N/A') . "\n";
        }
        
        if (strpos($types, 'device') !== false) {
            echo "\nDevice Analytics: " . json_encode($analytics['device'] ?? 'N/A') . "\n";
        }
        
        if (strpos($types, 'geography') !== false) {
            echo "\nGeographic Analytics: " . json_encode($analytics['geography'] ?? 'N/A') . "\n";
        }
    }
    
    return $analytics;
}

function getAnalyticsByTags($tags, $fromDate, $toDate, $types = 'count,geography') {
    return getQRAnalytics('tags', $tags, $fromDate, $toDate, $types);
}

// Usage - Get analytics by QR ID
$analytics = getQRAnalytics('qrid', ['Qf94b25d768294148'], '2025-02-01', '2025-02-25');
echo "Analytics: " . json_encode($analytics) . "\n";

// Usage - Get analytics by tags
$tagAnalytics = getAnalyticsByTags(['marketing', 'campaign'], '2025-02-01', '2025-02-25');

// Usage - Analyze performance for multiple QR codes
analyzeQRPerformance(['Qf94b25d768294148', 'Qf94b25d768294149'], 30, 'count,device,os,browser,geography');
?>
```

<Note>
  Analytics data is available for the last 2 years. For longer historical data, use the export endpoint to download data for offline analysis.
</Note>

<Warning>
  Large date ranges may result in slower response times. Consider breaking down requests into smaller date ranges for better performance.
</Warning>


## OpenAPI

````yaml POST /analytics/qr/
openapi: 3.0.0
info:
  title: Scanova API - Analytics
  description: >-
    Analytics endpoints for retrieving QR code scan data, statistics, and
    exporting analytics reports. These endpoints provide comprehensive insights
    into QR code performance, user behavior, and geographic distribution.
  version: 1.0.0
servers:
  - url: https://management.scanova.io
    description: Scanova Management API Server
security:
  - apiKeyAuth: []
paths:
  /analytics/qr/:
    post:
      tags:
        - Analytics
      summary: Get QR Code Analytics
      description: >-
        Retrieve analytics data for QR codes with various filtering and grouping
        options. Supports multiple analytics types including scan counts, device
        information, geographic data, and time-series analysis.
      parameters:
        - name: type
          in: query
          required: false
          description: >-
            Analytics type(s) to retrieve. Multiple values can be
            comma-separated.
          schema:
            type: string
            enum:
              - count
              - qr
              - device
              - os
              - browser
              - date
              - handset
              - geography
              - geo_location
          example: count,device,os
        - name: from
          in: query
          required: true
          description: 'Start date for analytics data (inclusive). Format: YYYY-MM-DD'
          schema:
            type: string
            format: date
          example: '2025-02-01'
        - name: to
          in: query
          required: true
          description: >-
            End date for analytics data (inclusive). Format: YYYY-MM-DD.
            Defaults to current date.
          schema:
            type: string
            format: date
          example: '2025-02-25'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - filter_by
                - q
              properties:
                filter_by:
                  type: string
                  enum:
                    - qrid
                    - tags
                  description: Filter by QR code ID or tags
                  example: qrid
                q:
                  type: array
                  items:
                    type: string
                  description: >-
                    Array of QR code IDs (if filter_by is 'qrid') or tags (if
                    filter_by is 'tags')
                  example:
                    - Qf94b25d768294148
      responses:
        '200':
          description: Analytics data retrieved successfully
          content:
            application/json:
              schema:
                type: object
                description: >-
                  Analytics data response containing various types of analytics
                  based on the requested fields. Response keys depend on the
                  'type' query parameter. Available analytics types: qr, count,
                  device, os, browser, date, handset, geography, geo_location,
                  age, day_time.
                additionalProperties: true
              examples:
                comprehensive_analytics:
                  summary: Comprehensive analytics response (all types requested)
                  value:
                    qr:
                      - - QR Code
                        - 1
                    count:
                      total: 1
                      elevation:
                        percent: 100
                        previous: 2
                        type: '-'
                        period:
                          start: '2025-10-11T18:07:00Z'
                          end: '2025-10-18T18:07:00Z'
                      unique: 1
                      unique_elevation:
                        percent: 100
                        previous: 2
                        type: '-'
                        period:
                          start: '2025-10-11T18:07:00Z'
                          end: '2025-10-18T18:07:00Z'
                      scan_qr: 0
                      scan_url: 1
                    device:
                      - - PC
                        - 1
                    os:
                      - - Mac OS X
                        - 1
                    date:
                      all:
                        - - '2025-10-18'
                          - 0
                        - - '2025-10-19'
                          - 0
                        - - '2025-10-20'
                          - 0
                        - - '2025-10-21'
                          - 0
                        - - '2025-10-22'
                          - 0
                        - - '2025-10-23'
                          - 0
                        - - '2025-10-24'
                          - 0
                        - - '2025-10-25'
                          - 1
                        - - '2025-10-26'
                          - 0
                      qr:
                        - - '2025-10-18'
                          - 0
                        - - '2025-10-19'
                          - 0
                        - - '2025-10-20'
                          - 0
                        - - '2025-10-21'
                          - 0
                        - - '2025-10-22'
                          - 0
                        - - '2025-10-23'
                          - 0
                        - - '2025-10-24'
                          - 0
                        - - '2025-10-25'
                          - 0
                        - - '2025-10-26'
                          - 0
                      url:
                        - - '2025-10-18'
                          - 0
                        - - '2025-10-19'
                          - 0
                        - - '2025-10-20'
                          - 0
                        - - '2025-10-21'
                          - 0
                        - - '2025-10-22'
                          - 0
                        - - '2025-10-23'
                          - 0
                        - - '2025-10-24'
                          - 0
                        - - '2025-10-25'
                          - 1
                        - - '2025-10-26'
                          - 0
                    handset:
                      - - Mac
                        - 1
                    browser:
                      - - Chrome
                        - 1
                    geography:
                      - country_code: Unknown
                        country_name: Unknown
                        region: Unknown
                        city: Unknown
                        count: 1
                    geo_location: []
                    age: []
                    day_time:
                      - - Sun
                        - '00'
                        - 0
                      - - Sun
                        - '01'
                        - 1
                      - - Sun
                        - '02'
                        - 0
                      - - Mon
                        - '09'
                        - 2
                      - - Mon
                        - '14'
                        - 3
                      - - Tue
                        - '18'
                        - 1
                      - - Wed
                        - '12'
                        - 2
                      - - Thu
                        - '16'
                        - 1
                      - - Fri
                        - '11'
                        - 2
                      - - Sat
                        - '20'
                        - 1
                count_only:
                  summary: Count analytics only
                  value:
                    count:
                      total: 1
                      elevation:
                        percent: 100
                        previous: 2
                        type: '-'
                        period:
                          start: '2025-10-11T18:07:00Z'
                          end: '2025-10-18T18:07:00Z'
                      unique: 1
                      unique_elevation:
                        percent: 100
                        previous: 2
                        type: '-'
                        period:
                          start: '2025-10-11T18:07:00Z'
                          end: '2025-10-18T18:07:00Z'
                      scan_qr: 0
                      scan_url: 1
                device_os_browser:
                  summary: Device, OS, and browser analytics
                  value:
                    device:
                      - - PC
                        - 1
                    os:
                      - - Mac OS X
                        - 1
                    browser:
                      - - Chrome
                        - 1
        '401':
          description: Unauthorized - Invalid API key
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: Authentication credentials were not provided.
      security:
        - apiKeyAuth: []
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        API key authentication. Enter your API key directly in the Authorization
        header.

````