Integration Guide
In this guide, you’ll learn how to use Middesk’s Website order to receive a detailed analysis of a business’s web presence.
Before getting started
- Contact Sales to enable our improved Web Analysis product on your account
- Ensure that you can authenticate against the Middesk API and create businesses
Step 1: Create a business and order Web Analysis
Web Analysis is a subproduct of the Website order. To create a business with a website order, you’ll need to submit the following Create Business request:
require 'uri'
require 'net/http'
url = URI("https://api.middesk.com/v1/businesses")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request["Authorization"] = '<Your Auth Token>'
request.body = "{\n \"name\": \"Joe's Bakery\",\n \"addresses\": [\n\t {\n\t\t \"full_address\": \"123 Main Street, Tampa, FL 33626\"\n\t }\n ],\n \"website\": {\n\t \"url\": \"www.joesbakery.com\"\n },\n\t\"orders\": [\n\t\t{\n\t\t \"product\": \"website\",\n\t\t \"subproducts\": [\"web_analysis\"]\n\t\t}\n\t]\n}"
response = http.request(request)
puts response.read_body
curl --request POST \
--url https://api.middesk.com/v1/businesses \
--header 'Authorization: <Your Auth Token>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Joe'\''s Bakery",
"addresses": [
{
"full_address": "123 Main Street, Tampa, FL 33626"
}
],
"website": {
"url": "www.joesbakery.com"
},
"orders": [
{
"product": "website",
"subproducts": ["web_analysis"]
}
]
}'
import http.client
conn = http.client.HTTPConnection("https://api.middesk.com")
payload = "{\n \"name\": \"Joe's Bakery\",\n \"addresses\": [\n\t {\n\t\t \"full_address\": \"123 Main Street, Tampa, FL 33626\"\n\t }\n ],\n \"website\": {\n\t \"url\": \"www.joesbakery.com\"\n },\n\t\"orders\": [\n\t\t{\n\t\t \"product\": \"website\",\n\t\t \"subproducts\": [\"web_analysis\"]\n\t\t}\n\t]\n}"
headers = {
'Content-Type': "application/json",
'Authorization': "<Your Auth Token>"
}
conn.request("POST", "/v1/businesses", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: '<Your Auth Token>'
},
body: '{"name":"Joe\'s Bakery","addresses":[{"full_address":"123 Main Street, Tampa, FL 33626"}],"website":{"url":"www.joesbakery.com"},"orders":[{"product":"website","subproducts":["web_analysis"]}]}'
};
fetch('https://api.middesk.com/v1/businesses', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
Note that the name, address, and website url are all required for Web Analysis.
Step 2: Analyze the outcome
Once your order completes, you can see the results in the GET /business payload or the business.updated
webhook, depending on your integration. For a high level summary of the outcome, you can look at the following review tasks:
Summary | Key |
---|---|
Is the website purchased but has no content? | website_parked |
Is the website online? | website_status |
Was there a match identified to the submitted office address? | web_address_verification |
Was there a match identified to the submitted business name? | web_business_name_verification |
Was there a match identified to the submitted person? | web_person_verification |
Was there a match identified to the submitted phone number? | web_phone_number_verification |
Was there a match identified to the submitted email address? | web_email_address_verification |
What is the web presence quality rating? | web_presence_quality |
If you’d like to see the results in more detail, you can look at the Website object in the payload as well as the specific Web Analysis Review Tasks in depth.
Additionally, any third party profiles associated with the business will be returned here as Profile objects under the top level profiles
key. This includes platforms such as Google, Facebook, LinkedIn, and more.
You can check the business's review tasks by requesting the full business payload using the Retrieve Business Endpoint. For example, you can use the Website Status Review Task to evaluate whether website is online.
require 'net/http'
require 'net/https'
require 'json'
def send_request
business_id = "<business_id>"
uri = URI("https://api.middesk.com/v1/businesses/#{business_id}")
# Create client
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
# Create Request
req = Net::HTTP::Get.new(uri)
# Add headers
req.add_field "Accept", "application/json"
# Add headers
req.add_field "Authorization", "Basic <api_key>"
# Fetch Request
res = http.request(req)
response = JSON.parse(res.body)
website_status_task = response['review']['tasks'].find { |task| task['key'] == 'website_status' }
if website_status_task['status'] == 'success'
puts 'Website online'
else
puts 'Website offline'
end
rescue StandardError => e
puts "HTTP Request failed (#{e.message})"
end
import requests
from requests.auth import HTTPBasicAuth
def send_request():
business_id = "<business_id>"
url = f"https://api.middesk.com/v1/businesses/{business_id}"
headers = {
"Accept": "application/json",
"Authorization": "Basic <api_key>"
}
try:
# Make the request
response = requests.get(url, headers=headers, auth=HTTPBasicAuth('<api_key>', ''))
# Parse the response JSON
response_data = response.json()
website_status_task = next((task for task in response_data['review']['tasks'] if task['key'] == 'website_status'), None)
if website_status_task and website_status_task['status'] == 'success':
print('Website online')
else:
print('Website offline')
except requests.exceptions.RequestException as e:
print(f"HTTP Request failed ({e})")
send_request()
const businessId = "<business_id>";
const url = `https://api.middesk.com/v1/businesses/${businessId}`;
const headers = {
"Accept": "application/json",
"Authorization": "Basic <api_key>"
};
try {
// Make the request using fetch
const response = await fetch(url, { headers });
// Check if the request was successful
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const responseData = await response.json();
const websiteStatusTask = responseData.review.tasks.find(task => task.key === 'website_status');
if (websiteStatusTask && websiteStatusTask.status === 'success') {
console.log('Website online');
} else {
console.log('Website offline');
}
} catch (error) {
console.error(`HTTP Request failed: ${error.message}`);
}
}
sendRequest();
Step 3: Inspect individual quality indicators
You can leverage web_presence_quality
to determine an overall quality rating of "High", "Moderate", "Low", or "Not Available" of the business's web presence. Going one step further, we can inspect each quality indicator used to determine the overall quality rating and optionally, derive an outcome based on your own defined heuristics.
Indicator Introspection
One example of a potential use case for directly inspecting the indicators is in the case of evaluating new businesses. Naturally a newly formed business may have a recently registered domain and possibly is perfectly okay for the site to not display a high amount of content diversity, given its recent inception. If that is the case, you may wish to explicitly ignore those ratings to determine your desired outcome.
Here's a look at the current quality indicators and their respective keys within the website
object. Each indicator includes a rating
field of its own, yielding a "positive", "neutral", or "negative" rating for each category type. If the indicator cannot be accurately determined for any reason, the indicator will absent from the payload.
Quality Indicator | Description | Key |
---|---|---|
Broken links | An evaluation of links found on the website leading to errors or nonexistent pages | broken_links |
Compliance info | An evaluation of compliance-related information, such as terms of service, privacy policy, etc. can be found on the business's website | compliance_info |
Contact info | An evaluation of contact information found within the content. You can leverage the other review tasks associated with the Website order to determine matches with submitted contact information. | contact_info |
Content diversity | An evaluation of the variation and type of information the website presents | content_diversity |
Domain age | An evaluation of how long as the domain been registered for | domain_age |
Filler text | An evaluation of content for any placeholder or filler text, eg. Lorem Ipsum | filler_text |
Https | An evaluation of HTTPS/TLS support | https |
Image quality | An evaluation of images to identify blurry or stock images | image_quality |
Last updated | An evaluation of how long ago was the wesbite last modified | last_updated |
Page count | An evaluation of the total number of internal pages found on the website | page_count |
Spelling and grammar | An evaluation of spelling and grammatical mistakes and inconsistencies | spelling_and_grammar |
Top Level Domain | An evaluation of the TLD with respect to the website's quality | top_level_domain |
Update frequency | An evaluation of how often the website's content is updated | update_frequency |
US Business Presence | An evaluation of website signals that suggest the business operates within the United States | us_business_presence |
You can retrieve these additional website details via the https://api.middesk.com/businesses/{id}/website
endpoint. Here's an example iterating and printing out the sample business's website's quality indicator ratings:
require 'net/http'
require 'uri'
require 'json'
require 'base64'
def print_indicators_quality_ratings
# Replace with your actual business ID and API key
business_id = "51c4b91e-f324-467b-86b5-9e0155bcc251" # Example business ID
api_key = "YOUR_API_KEY_HERE" # Replace with your actual API key
uri = URI.parse("https://api.middesk.com/v1/businesses/#{business_id}/website")
# Create the HTTP Basic Auth header
auth = Base64.strict_encode64("#{api_key}:")
headers = {
"Accept" => "application/json",
"Authorization" => "Basic #{auth}"
}
# Create the HTTP request
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri, headers)
begin
# Make the request
response = http.request(request)
# Raise an error if the response is not successful
unless response.is_a?(Net::HTTPSuccess)
puts "HTTP Request failed (#{response.code} #{response.message})"
return
end
# Parse the JSON response
data = JSON.parse(response.body)
# Navigate to the indicators
indicators = data.dig('rating', 'indicators') || []
if indicators.empty?
puts "No indicators found in the response."
return
end
# Print each indicator's name and rating
puts "Indicators' Quality Ratings:"
puts "----------------------------"
indicators.each do |indicator|
name = indicator['name'] || 'Unknown Indicator'
rating = indicator['rating'] || 'No Rating'
description = indicator['description'] || ''
puts "#{name}: #{rating} (#{description})"
end
rescue JSON::ParserError
puts "Error parsing JSON response."
rescue StandardError => e
puts "An error occurred: #{e.message}"
end
end
print_indicators_quality_ratings
# Sample Output:
# Indicators' Quality Ratings:
# ----------------------------
# Domain age: positive (3 to 10 years old)
# Compliance info: positive (Found)
# Spelling and grammar: positive (Good)
# Contact info: positive (Found)
# Content diversity: positive (High)
# Https: positive (Enabled)
# Broken links: negative (Some broken)
# Filler text: positive (Minimal)
# Page count: positive (High)
# Image quality: positive (Good)
import requests
from requests.auth import HTTPBasicAuth
def print_indicators_quality_ratings():
# Replace with your actual business ID and API key
business_id = "51c4b91e-f324-467b-86b5-9e0155bcc251" # Example business ID
api_key = "YOUR_API_KEY_HERE" # Replace with your actual API key
url = f"https://api.middesk.com/v1/businesses/{business_id}/website"
headers = {
"Accept": "application/json"
}
try:
# Make the GET request with HTTP Basic Authentication
response = requests.get(url, headers=headers, auth=HTTPBasicAuth(api_key, ''))
# Raise an exception if the request was unsuccessful
response.raise_for_status()
# Parse the JSON response
data = response.json()
# Navigate to the indicators
indicators = data.get('rating', {}).get('indicators', [])
if not indicators:
print("No indicators found in the response.")
return
# Print each indicator's name and rating
print("Indicators' Quality Ratings:")
print("----------------------------")
for indicator in indicators:
name = indicator.get('name', 'Unknown Indicator')
rating = indicator.get('rating', 'No Rating')
description = indicator.get('description', '')
print(f"{name}: {rating} ({description})")
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred: {http_err}") # e.g., 404 Not Found
except requests.exceptions.RequestException as req_err:
print(f"Request error occurred: {req_err}") # Other request-related errors
except ValueError:
print("Error parsing JSON response.")
except KeyError as key_err:
print(f"Missing expected data in response: {key_err}")
if __name__ == "__main__":
print_indicators_quality_ratings()
''' Sample output
Indicators' Quality Ratings:
----------------------------
Domain age: positive (3 to 10 years old)
Compliance info: positive (Found)
Spelling and grammar: positive (Good)
Contact info: positive (Found)
Content diversity: positive (High)
Https: positive (Enabled)
Broken links: negative (Some broken)
Filler text: positive (Minimal)
Page count: positive (High)
Image quality: positive (Good)
'''
const axios = require('axios');
async function printIndicatorsQualityRatings() {
// Replace with your actual business ID and API key
const businessId = "51c4b91e-f324-467b-86b5-9e0155bcc251"; // Example business ID
const apiKey = "YOUR_API_KEY_HERE"; // Replace with your actual API key
const url = `https://api.middesk.com/v1/businesses/${businessId}/website`;
try {
const response = await axios.get(url, {
headers: {
'Accept': 'application/json',
'Authorization': `Basic ${Buffer.from(`${apiKey}:`).toString('base64')}`
}
});
const data = response.data;
// Navigate to the indicators
const indicators = data.rating && data.rating.indicators ? data.rating.indicators : [];
if (indicators.length === 0) {
console.log("No indicators found in the response.");
return;
}
// Print each indicator's name and rating
console.log("Indicators' Quality Ratings:");
console.log("----------------------------");
indicators.forEach(indicator => {
const name = indicator.name || 'Unknown Indicator';
const rating = indicator.rating || 'No Rating';
const description = indicator.description || '';
console.log(`${name}: ${rating} (${description})`);
});
} catch (error) {
if (error.response) {
// Server responded with a status other than 2xx
console.error(`HTTP error occurred: ${error.response.status} ${error.response.statusText}`);
} else if (error.request) {
// No response received
console.error("No response received:", error.request);
} else {
// Other errors
console.error("Error:", error.message);
}
}
}
printIndicatorsQualityRatings();
// Sample Output:
// Indicators' Quality Ratings:
// ----------------------------
// Domain age: positive (3 to 10 years old)
// Compliance info: positive (Found)
// Spelling and grammar: positive (Good)
// Contact info: positive (Found)
// Content diversity: positive (High)
// Https: positive (Enabled)
// Broken links: negative (Some broken)
// Filler text: positive (Minimal)
// Page count: positive (High)
// Image quality: positive (Good)
Looking for a deeper dive?
The API also exposes a source
object for each indicator to illustrate how the indicator quality rating was derived. This includes a human-readable explanation
and, when relevant, examples
from the retrieved dataset respective to the indicator returned. For example, the image_quality
indicator will return a list of source URLs for any stock images detected, the spelling_and_grammar
indicator will list citations for any found mistakes or inconsistencies, and the broken_links
indicator will return a list of URLs found on the website that do not resolve.
To access this expanded view, you simply need to add the query parameter include
with the value indicator_details
to the aforementioned business website endpoint.
ie.https://api.middesk.com/businesses/{id}/website?include=indicator_details
eg. expanded quality rating indicator with new source
key
{
"type": "image_quality",
"name": "Image quality",
"rating": "negative",
"source": {
"examples": [
{
"link": "https://images.unsplash.com/photo-1637684666451-423047d6bf5e?ixid=M3wzOTE5Mjl8MHwxfHNlYXJjaHw4fHxzdGFydHVwfGVufDB8fHx8MTcxNDg3ODI0Nnww\u0026ixlib=rb-4.0.3\u0026auto=format\u0026fit=crop\u0026w=1920",
"location": "https://example.com/contact",
"classification": "stock_image"
},
{
"link": "https://images.unsplash.com/photo-1588856122867-363b0aa7f598?ixid=M3wzOTE5Mjl8MHwxfHNlYXJjaHw1fHxzdGFydHVwfGVufDB8fHx8MTcxNDg3ODI0Nnww\u0026ixlib=rb-4.0.3\u0026auto=format\u0026fit=crop\u0026w=328\u0026h=332",
"location": "https://example.com/",
"classification": "stock_image"
},
{
"link": "https://images.unsplash.com/photo-1519389950473-47ba0277781c?ixid=M3wzOTE5Mjl8MHwxfHNlYXJjaHwyfHxzdGFydHVwfGVufDB8fHx8MTcxNDg3ODI0Nnww\u0026ixlib=rb-4.0.3\u0026auto=format\u0026fit=crop\u0026w=1224\u0026h=400",
"location": "https://example.com/",
"classification": "stock_image"
},
{
"link": "https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixid=M3wzOTE5Mjl8MHwxfHNlYXJjaHw2fHxzdGFydHVwfGVufDB8fHx8MTcxNDg3ODI0Nnww\u0026ixlib=rb-4.0.3\u0026auto=format\u0026fit=crop\u0026w=606\u0026h=304",
"location": "https://example.com/about",
"classification": "stock_image"
},
{
"link": "https://images.unsplash.com/photo-1553729459-efe14ef6055d?auto=format\u0026fit=crop\u0026w=328\u0026h=264",
"location": "https://example.com/company",
"classification": "stock_image"
}
],
"explanation": "We found many stock images."
},
"value": "poor",
"description": "Poor"
},
Updated 2 days ago