Products

SIGN UPLOG IN
Nudity Detection

Models / QR code moderation

QR Code Moderation in Images/Videos

Overview

The QR Code Moderation API is useful to detect if an image or video contains QR codes and determine if the content of those QR codes is problematic.

Problematic QR codes are ones that contain profanity, or personal information, or links to bad websites and URLs such as adult content, malware, illegal or otherwise unwanted content. The API will tell you what type of content has been found in QR codes, if any.

Just like our other Image Moderation APIs, this API performs the analysis entirely automatically. There are no humans reviewing your content. This helps us achieve very fast turnaround times — less than a second — and very high scalablity.

boxes showing a qr code found on a sleeve with a link to a harmful website
Image containing a flagged QR code linking to a harmful website

Principles

The QR Code Moderation API is a robust way to sanitize images or videos that might contain QR codes. It works for images with multiple QR codes, and works out-of-the-box with QR codes of various sizes and under different angles.

The QR Code Moderation API for Images works in several steps:

  1. Detection of QR codes contained in the image
  2. Decoding of the QR code content
  3. Analysis of the content through our moderation engine

Use-cases

  • Protect users from nefarious links embedded in QR codes
  • Restrict bypass techniques attempting to lure your users away to other websites/apps through QR codes
  • Flag users posting profanity, obscene or illegal content through QR codes

Categories

The rules are grouped into categories, to help you implement custom filters based on the type of flagged content.

CategoryDescription
link

URLs to external websites and pages. We can flag domains known to host unsafe or unwanted content

read more
personal (pii)

The personal category contains following types of terms and expressions:

  • email — email addresses, including obfuscated ones
  • phone_number_** — phone numbers that are valid numbers in the countries specified through the opt_countries parameter. This includes obfuscated numbers
  • username —  usernames
  • ssn — US social security numbers
  • ip — IP addresses, both IPv4 and IPv6

read more

profanity

The profanity category contains following types of terms and expressions:

  • sexual — term or expression that refers to sexual acts, sexual organs, body parts or bodily fluids typically associated with sexual acts
  • discriminatory — discriminatory and derogatory content. Mostly hate speech that instigates violence or hate against groups based on specific characteristics such as religion, national or ethnic origin, sexual orientation or gender identity
  • insult — words or phrases that undermine the dignity or honor of an individual, that are signs of disrespect and are generally used to refer to someone
  • inappropriate — inappropriate language: swear words, slang, familiar/informal or socially inappropriate/unacceptable words or phrases to describe something, or to talk to someone
  • grawlix — string of typographical symbols that are typically used in place of obscenity or profanity

read more

spam

expressions commonly associated with spam or with circumvention, i.e. attempts to send or lure the user to another platform

Link and URL Moderation in QR codes

Links and URLs will be detected and flagged as such in QR codes. They will be returned under the link key in the API response. Here is an example:

            
            
{
    "qr": {
        "link": [
            {
                "type": "url",
                "match": "http://harmfulsiteexample.com",
                "category": "unsafe"
            }
        ]
    }
}
            
        

In addition to detecting URLs in QR codes, you can also moderate the link to determine if the link is unsafe, contains adult or unwanted content or is deceptive, through the category field. More details are available on the URL and link moderation page

Profanity Detection in QR codes

Profanity Detection will enable you to detect insults, discriminatory content, sexual content or other inappropriate words and phrases in your images.

It is a lot stronger than word-based filters. It uses advanced language analysis to detect objectionable content, even when users specifically attempt to circumvent your filters. It covers obfuscation techniques such as repetitions, insertions, spelling mistakes, leet speak and more. Learn more on our Text Moderation Engine.

            
            
{
    "qr": {
        "profanity": [
            {
                "type": "insult",
                "match": "idiot",
                "intensity": "medium"
            }
        ]
    }
}
            
        

Personal Information Detection in QR codes

Email addresses

Email addresses will be detected and flagged as such in the image.

Phone numbers

Phone numbers will be detected and flagged as such in the image.

You can select the countries to be covered through the opt_countries parameter. Provide a comma-separated list of the ISO 3166 2-letter country codes. For instance us for the United-States, fr for France. See the full list of supported countries.

If you do not specify any country, the API will default to the following list of countries: United States us, France fr, United Kingdom gb

Languages and Recommendations

Languages

English is the default language used for the profanity filtering.

You can set a different language with the opt_lang parameter. To do so use the following codes:

LanguageCode
English (default)en
Chinesezh
Danishda
Dutchnl
Finnishfi
Frenchfr
Germande
Italianit
Norwegianno
Polishpl
Portuguesept
Spanishes
Swedishsv
Tagalog / Filipinotl
Turkishtr

Other languages are available upon request. Please get in touch.

Use the model (images)

If you haven't already, create an account to get your own API keys.

Moderate QR codes in images

Let's say you want to moderate the following image:

You can either share a URL to the image, or upload the raw binary image.

Option 1: Send image URL

Here's how to proceed if you choose to share the image URL:


curl -X GET -G 'https://api.sightengine.com/1.0/check.json' \
    -d 'models=qr-content' \
    -d 'api_user={api_user}&api_secret={api_secret}' \
    --data-urlencode 'url=https://sightengine.com/assets/img/examples/example-qr-600.jpg'


# this example uses requests
import requests
import json

params = {
  'url': 'https://sightengine.com/assets/img/examples/example-qr-600.jpg',
  'models': 'qr-content',
  'api_user': '{api_user}',
  'api_secret': '{api_secret}'
}
r = requests.get('https://api.sightengine.com/1.0/check.json', params=params)

output = json.loads(r.text)


$params = array(
  'url' =>  'https://sightengine.com/assets/img/examples/example-qr-600.jpg',
  'models' => 'qr-content',
  'api_user' => '{api_user}',
  'api_secret' => '{api_secret}',
);

// this example uses cURL
$ch = curl_init('https://api.sightengine.com/1.0/check.json?'.http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$output = json_decode($response, true);


// this example uses axios
const axios = require('axios');

axios.get('https://api.sightengine.com/1.0/check.json', {
  params: {
    'url': 'https://sightengine.com/assets/img/examples/example-qr-600.jpg',
    'models': 'qr-content',
    'api_user': '{api_user}',
    'api_secret': '{api_secret}',
  }
})
.then(function (response) {
  // on success: handle response
  console.log(response.data);
})
.catch(function (error) {
  // handle error
  if (error.response) console.log(error.response.data);
  else console.log(error.message);
});

See request parameter description

ParameterTypeDescription
mediabinaryimage to analyze
modelsstringcomma-separated list of models to apply
api_userstringyour API user id
api_secretstringyour API secret

Option 2: Send raw image

Here's how to proceed if you choose to upload the raw image:


curl -X POST 'https://api.sightengine.com/1.0/check.json' \
    -F 'media=@/path/to/image.jpg' \
    -F 'models=qr-content' \
    -F 'api_user={api_user}' \
    -F 'api_secret={api_secret}'


# this example uses requests
import requests
import json

params = {
  'models': 'qr-content',
  'api_user': '{api_user}',
  'api_secret': '{api_secret}'
}
files = {'media': open('/path/to/image.jpg', 'rb')}
r = requests.post('https://api.sightengine.com/1.0/check.json', files=files, data=params)

output = json.loads(r.text)


$params = array(
  'media' => new CurlFile('/path/to/image.jpg'),
  'models' => 'qr-content',
  'api_user' => '{api_user}',
  'api_secret' => '{api_secret}',
);

// this example uses cURL
$ch = curl_init('https://api.sightengine.com/1.0/check.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
curl_close($ch);

$output = json_decode($response, true);


// this example uses axios and form-data
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

data = new FormData();
data.append('media', fs.createReadStream('/path/to/image.jpg'));
data.append('models', 'qr-content');
data.append('api_user', '{api_user}');
data.append('api_secret', '{api_secret}');

axios({
  method: 'post',
  url:'https://api.sightengine.com/1.0/check.json',
  data: data,
  headers: data.getHeaders()
})
.then(function (response) {
  // on success: handle response
  console.log(response.data);
})
.catch(function (error) {
  // handle error
  if (error.response) console.log(error.response.data);
  else console.log(error.message);
});

See request parameter description

ParameterTypeDescription
mediabinaryimage to analyze
modelsstringcomma-separated list of models to apply
api_userstringyour API user id
api_secretstringyour API secret

API response

The API will then return a JSON response with the following structure:

                  
                  
{
  "status": "success",
  "request": {
      "id": "req_22Qd0gUNmRH4GCYLvYtN6",
      "timestamp": 1512483673.1405,
      "operations": 1
  },
  "qr": {
      "personal": [],
      "link": [
          {
              "type": "url",
              "match": "http://harmfulsiteexample.com"
          }
      ],
      "social": [],
      "profanity": [],
      "spam": []
  },
  "media": {
      "id": "med_22Qdfb5s97w8EDuY7Yfjp",
      "uri": "https://sightengine.com/assets/img/examples/example-qr-600.jpg"
  }
}


              

Use model (Videos)

Moderate QR codes in videos

Option 1: Short video

Here's how to proceed to analyze a short video (less than 1 minute):


curl -X POST 'https://api.sightengine.com/1.0/video/check-sync.json' \
  -F 'media=@/path/to/video.mp4' \
  -F 'models=qr-content' \
  -F 'api_user={api_user}' \
  -F 'api_secret={api_secret}'


# this example uses requests
import requests
import json

params = {
  # specify the models you want to apply
  'models': 'qr-content',
  'api_user': '{api_user}',
  'api_secret': '{api_secret}'
}
files = {'media': open('/path/to/video.mp4', 'rb')}
r = requests.post('https://api.sightengine.com/1.0/video/check-sync.json', files=files, data=params)

output = json.loads(r.text)


$params = array(
  'media' => new CurlFile('/path/to/video.mp4'),
  // specify the models you want to apply
  'models' => 'qr-content',
  'api_user' => '{api_user}',
  'api_secret' => '{api_secret}',
);

// this example uses cURL
$ch = curl_init('https://api.sightengine.com/1.0/video/check-sync.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
curl_close($ch);

$output = json_decode($response, true);


// this example uses axios and form-data
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

data = new FormData();
data.append('media', fs.createReadStream('/path/to/video.mp4'));
// specify the models you want to apply
data.append('models', 'qr-content');
data.append('api_user', '{api_user}');
data.append('api_secret', '{api_secret}');

axios({
  method: 'post',
  url:'https://api.sightengine.com/1.0/video/check-sync.json',
  data: data,
  headers: data.getHeaders()
})
.then(function (response) {
  // on success: handle response
  console.log(response.data);
})
.catch(function (error) {
  // handle error
  if (error.response) console.log(error.response.data);
  else console.log(error.message);
});

See request parameter description

ParameterTypeDescription
mediabinaryimage to analyze
modelsstringcomma-separated list of models to apply
intervalfloatframe interval in seconds, out of 0.5, 1, 2, 3, 4, 5 (optional)
api_userstringyour API user id
api_secretstringyour API secret

Option 2: Long video

Here's how to proceed to analyze a long video. Note that if the video file is very large, you might first need to upload it through the Upload API.


curl -X POST 'https://api.sightengine.com/1.0/video/check.json' \
  -F 'media=@/path/to/video.mp4' \
  -F 'models=qr-content' \
  -F 'callback_url=https://yourcallback/path' \
  -F 'api_user={api_user}' \
  -F 'api_secret={api_secret}'


# this example uses requests
import requests
import json

params = {
  # specify the models you want to apply
  'models': 'qr-content',
  # specify where you want to receive result callbacks
  'callback_url': 'https://yourcallback/path',
  'api_user': '{api_user}',
  'api_secret': '{api_secret}'
}
files = {'media': open('/path/to/video.mp4', 'rb')}
r = requests.post('https://api.sightengine.com/1.0/video/check.json', files=files, data=params)

output = json.loads(r.text)


$params = array(
  'media' => new CurlFile('/path/to/video.mp4'),
  // specify the models you want to apply
  'models' => 'qr-content',
  // specify where you want to receive result callbacks
  'callback_url' => 'https://yourcallback/path',
  'api_user' => '{api_user}',
  'api_secret' => '{api_secret}',
);

// this example uses cURL
$ch = curl_init('https://api.sightengine.com/1.0/video/check.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
curl_close($ch);

$output = json_decode($response, true);


// this example uses axios and form-data
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

data = new FormData();
data.append('media', fs.createReadStream('/path/to/video.mp4'));
// specify the models you want to apply
data.append('models', 'qr-content');
// specify where you want to receive result callbacks
data.append('callback_url', 'https://yourcallback/path');
data.append('api_user', '{api_user}');
data.append('api_secret', '{api_secret}');

axios({
  method: 'post',
  url:'https://api.sightengine.com/1.0/video/check.json',
  data: data,
  headers: data.getHeaders()
})
.then(function (response) {
  // on success: handle response
  console.log(response.data);
})
.catch(function (error) {
  // handle error
  if (error.response) console.log(error.response.data);
  else console.log(error.message);
});

See request parameter description

ParameterTypeDescription
mediabinaryimage to analyze
callback_urlstringcallback URL to receive moderation updates (optional)
modelsstringcomma-separated list of models to apply
intervalfloatframe interval in seconds, out of 0.5, 1, 2, 3, 4, 5 (optional)
api_userstringyour API user id
api_secretstringyour API secret

Option 3: Live-stream

Here's how to proceed to analyze a live-stream:


curl -X GET -G 'https://api.sightengine.com/1.0/video/check.json' \
    --data-urlencode 'stream_url=https://domain.tld/path/video.m3u8' \
    -d 'models=qr-content' \
    -d 'callback_url=https://your.callback.url/path' \
    -d 'api_user={api_user}' \
    -d 'api_secret={api_secret}'


# if you haven't already, install the SDK with 'pip install sightengine'
from sightengine.client import SightengineClient
client = SightengineClient('{api_user}','{api_secret}')
output = client.check('qr-content').video('https://domain.tld/path/video.m3u8', 'https://your.callback.url/path')


// if you haven't already, install the SDK with 'composer require sightengine/client-php'
use \Sightengine\SightengineClient;
$client = new SightengineClient('{api_user}','{api_secret}');
$output = $client->check(['qr-content'])->video('https://domain.tld/path/video.m3u8', 'https://your.callback.url/path');


// if you haven't already, install the SDK with 'npm install sightengine --save'
var sightengine = require('sightengine')('{api_user}', '{api_secret}');
sightengine.check(['qr-content']).video('https://domain.tld/path/video.m3u8', 'https://your.callback.url/path').then(function(result) {
    // The API response (result)
}).catch(function(err) {
    // Handle error
});

See request parameter description

ParameterTypeDescription
stream_urlstringURL of the video stream
callback_urlstringcallback URL to receive moderation updates (optional)
modelsstringcomma-separated list of models to apply
intervalfloatframe interval in seconds, out of 0.5, 1, 2, 3, 4, 5 (optional)
api_userstringyour API user id
api_secretstringyour API secret

Moderation result

The Moderation result will be provided either directly in the request response (for sync calls, see below) or through the callback URL your provided (for async calls).

Here is the structure of the JSON response with moderation results for each analyzed frame under the data.frames array:

            
                  
{
  "status": "success",
    "request": {
    "id": "req_gmgHNy8oP6nvXYaJVLq9n",
    "timestamp": 1717159864.348989,
    "operations": 21
  },
  "data": {
  "frames": [
    {
      "info": {
        "id": "med_gmgHcUOwe41rWmqwPhVNU_1",
        "position": 0
      },
      "qr": {
        "personal": [],
        "link": [],
        "social": [],
        "profanity": [],
        "spam": []
      },
     },
     ...
    ]
  },
  "media": {
    "id": "med_gmgHcUOwe41rWmqwPhVNU",
    "uri": "yourfile.mp4"
  },
}


            

You can use the classes under the qr object to detect and analyze QR codes in the video.

Any other needs?

See our full list of Text models for details on other filters and checks you can run on your text content. You might also want to check our Image & Video models to moderate images and videos. This includes moderation of text in images/videos.

Was this page helpful?