diff --git a/README.md b/README.md
index 75707dedba7cc7a4987fa002c0a8ed73db49f925..f89df05cd2bcb28d9eb4c679ffd171f8aab19669 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
 # Cortex analyzers
 
+Custom Cortex analyzers and responders
+
+
diff --git a/analyzers/NERD/nerd.json b/analyzers/NERD/nerd.json
new file mode 100644
index 0000000000000000000000000000000000000000..76bf20e998fd05ef935b26ba3bc94aeb37dbfc34
--- /dev/null
+++ b/analyzers/NERD/nerd.json
@@ -0,0 +1,28 @@
+{
+  "name": "NERD",
+  "version": "1.0",
+  "author": "Vaclav Bartos, CESNET",
+  "url": "TODO (not public yet)",
+  "license": "AGPL-V3",
+  "description": "Get Reputation score and other basic information from Network Entity Reputation Database (NERD)",
+  "dataTypeList": ["ip"],
+  "baseConfig": "NERD",
+  "command": "NERD/nerd_analyzer.py",
+  "configurationItems": [
+    {
+      "name": "key",
+      "description": "API key",
+      "type": "string",
+      "multi": false,
+      "required": true
+    },
+    {
+      "name": "url",
+      "description": "Base URL of the NERD instance",
+      "type": "string",
+      "multi": false,
+      "required": false,
+      "defaultValue": "https://nerd.cesnet.cz/nerd/"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/analyzers/NERD/nerd_analyzer.py b/analyzers/NERD/nerd_analyzer.py
new file mode 100644
index 0000000000000000000000000000000000000000..f297d1790708a71f7e93a694f77d7cdb791bd43f
--- /dev/null
+++ b/analyzers/NERD/nerd_analyzer.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+
+import requests
+from cortexutils.analyzer import Analyzer
+
+class NERDAnalyzer(Analyzer):
+    def __init__(self):
+        Analyzer.__init__(self)
+        self.base_url = self.get_param('config.url', None, 'Missing URL of NERD.')
+        if not self.base_url.endswith('/'):
+            self.base_url += '/'
+        self.api_key = self.get_param('config.key', None, 'Missing API key for NERD.')
+
+    def summary(self, raw):
+        """Returns a summary, needed for 'short.html' template, based on the full report"""
+
+        taxonomies = []
+        if 'message' in raw:
+            # IP wasn't found
+            taxonomies.append(self.build_taxonomy('safe', 'NERD', 'Rep', 'no-data'))
+        else:
+            # Reputation score (set level/color according to the score)
+            rep = round(raw['rep'], 3)
+            rep_level = 'safe' if rep < 0.02 else ('suspicious' if rep <= 0.5 else 'malicious')
+            taxonomies.append(self.build_taxonomy(rep_level, 'NERD', 'Rep', rep))
+
+            # Number of blacklists
+            if raw['blacklists']:
+                taxonomies.append(self.build_taxonomy('malicious', 'NERD', 'Blacklists', len(raw['blacklists'])))
+
+            # Tags
+            for tag in raw['tags']:
+                # TODO: filter tags, set different levels
+                taxonomies.append(self.build_taxonomy('info', 'NERD', 'Tag', tag))
+
+        return {'taxonomies': taxonomies}
+
+    def artifacts(self, raw):
+        """Returns a list of indicators extracted from reply (empty in this case)"""
+        return [] # TODO add hostname as a new indicator?
+
+    def run(self):
+        """Main function run by Cortex to analyze an observable."""
+        print("RUN")
+        if self.data_type != 'ip':
+            self.error("Invalid data type, only IP addresses are supported")
+            return
+        ip = self.get_data()
+        print("ip:", ip)
+
+        # Get data from server
+        url = '{}api/v1/ip/{}'.format(self.base_url, ip)
+        headers = {'Authorization': self.api_key}
+        try:
+            resp = requests.get(url, headers=headers)
+        except Exception as e:
+            self.error("Error when trying to contact server: {}".format(e))
+            return
+
+        # Parse received data
+        try:
+            data = resp.json()
+        except ValueError:
+            self.error("Invalid response received from server.")
+            return
+
+        if resp.status_code == 404:
+            # IP not found in NERD's DB (i.e. it wasn't reported as malicious)
+            self.report({
+                'rep': 0.0,
+                'message': '{} not found in NERD, i.e. there are no recent reports of malicious activity.'.format(ip)
+            })
+            return
+        elif resp.status_code == 200:
+            # Success, IP data received - format as output for Cortex
+            try:
+                self.report({
+                    'rep': data['rep'], # reputation score (number between 0.0 to 1.0)
+                    'hostname': data['hostname'], # result of DNS PTR qeury
+                    'asn': data['asn'], # list of ASNs announcing the IP (usually just one)
+                    'country': data['geo']['ctry'], # Geolocation - two-letter country code
+                    'blacklists': data['bl'], # List of blacklists the IP is listed on
+                    'tags': [t['n'] for t in data['tags'] if t.get('c', 1.0) >= 0.5] # List of tags (with confidence >= 50%)
+                })
+            except KeyError as e:
+                self.error("Invalid response received from server, missing field: {}".format(e))
+        else:
+            # Unexpected status code, there should be an 'error' field with error message
+            self.error("Error: {} {}".format(resp.status_code, data.get('error', '(no error message)')))
+            return
+
+
+if __name__ == '__main__':
+    NERDAnalyzer().run()
diff --git a/analyzers/NERD/requirements.txt b/analyzers/NERD/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..58023889324134d497fc817c65c6607143810207
--- /dev/null
+++ b/analyzers/NERD/requirements.txt
@@ -0,0 +1,2 @@
+requests
+cortexutils
\ No newline at end of file