Static event website generator


EQEvents is a static website generator for SeisComP XML event parameters. It can run in a spooler mode or process single files. It uses a template engine to create the HTML files. It features an index page and event detail page. More information can be added though Plugins.

EQEvents is meant to run as output service for GDS (gempa dissemination server).


The different EQEvents features are implemented by various plugins which may be activated by adding a plugin to the list of processingPlugins, e.g., browser,gds,gis,leaflet,rss,search,shakemap.

The following plugins exist:




Adds a calendar based event browser.


Adds bulletins containing additional information generated by an external source to an event detail page. This plugin is rarely used and requires customization.


Updates gempa dissemination server (GDS) database with event processing information. It is recommended to activate this plugin if EQEvents is triggered by GDS.


Generates a detailed event map using gempa image server (GIS).


Generates a dynamic map showing the events of the current event table on the index page, in the event browser and the event search.


Notifies connected clients about event and bulletin updates through a socket io interface. This plugin is rarely used and requires customization.


Adds distance, azimuth, and polar plot to event detail page.


Creates a RSS feet users may subscribe to.


Adds an event search. Note: The search function is implemented as a WSGI script and needs additional installation steps, described in Dynamic Content - The Search and Feedback Plugins.


Adds an email feedback form. Note: The feedback function is implemented as a WSGI script and needs additional installation steps, described in Dynamic Content - The Search and Feedback Plugins.


Generates a shake map using gempa’s autosigma module.

System dependencies which may be required by the plugins:

  • python-matplotlib

  • python-jinja2



To process a single XML file run EQEvents and pass it an XML file:

eqevents -i event.xml --debug


In contrast to a typical GDS service EQEvents is not monitored by GDS but runs as a SeisComP module. The $SEISCOMP_ROOT/etc/gds.cfg only defines a spool directory but no spooler nor filter command. The same directory needs to be configured in $SEISCOMP_ROOT/etc/eqevents.cfg. If an event matches the GDS dissemination criteria or an operator manually disseminated an event the GDS will place a *.content file containing the SeisComP XML and a *.address file into the spool directory where they are found by EQEvents.

Processing details:

  • The file name of the address and content file must match.

  • Files with the same name but different extension are processed as auxiliary files.

  • Each file found is deleted either after processing or due to wrong the file name format.

  • The processing starts when the content file is found.

  • The content file contains a match information according to the GDS dissemination rules, see ignoreMatch.

  • If multiple files for the same event are found then only the newest one is processed and the others are deleted.

  • The file name format is <SECONDS.MILLIS>-<GDSID>-<EVENTID>-<SERVICE>[-FILTER].<EXT>




    Time of dissemination


    ID of the dissemination procedure used to report back the dissemination status


    Event ID used to skip older files of same event


    GDS service name, unused


    GDS custom filter name, unused


    File name extension


If a template was changed or new plugins have been added all static pages need to be reprocessed. As a precondition for this the event XML data must be available, see backupXML.

To initiate reprocessing stop EQEvents and run it using the reprocess command-line option.

eqevents --reprocess


EQEvents uses templates in a well defined structure. The path to the template directory can be configured with templateDirectory. The structure is as follows:


Base template inherited by almost all templates


RSS web feed


Index page


Leaflet map, used in: index, browser, results


Search result page


Search parameter page


Event list table, used in index, browser, results


Browser day page showing all events of a particular day


Browser index page showing all years


Browser month page showing all days


Browser year page showing all months


Event details arrival list


Event details base template


Event details overview page


Event details quality plots

Templates are processed by Python Jinja and follow its documented syntax. Each template receives a context with several variables defined.


The EventParameters structure parsed from XML converted to a Python object. Attributes are accessible following the SeisComP ML schema names. They are mapped directly from the XML tag/attribute names. Below a simple example how to access all picks in the EventParameters object in template syntax:

{% for p in ep.pick %}
{{ p.waveformID.networkCode }}.{{ p.waveformID.stationCode }} {{ p.time.value|qmldate|date }}
{% endfor %}

The special filter qmldate is a special filter added by EQEvents to convert a date string from SeisComP ML to an Python datetime object. That object can then be further processed with the Jinja date filter.


The event object currently processed.


The preferred origin of the currently processed event.


The preferred focal mechanism of the currently processed event.


The preferred magnitude of the currently processed event.


The POOL that maps a publicID to an object.

{% for arr in origin.arrival %}
{% p = POOL[arr.pickID] %}
{% if p %}
<div>{{ p.time.value|qmldate|data }}</div>
{% else %}
<div class="error">Referenced pick {{ arr.pickID }} not available</div>
{% endif %}
{% endfor %}

This makes it easier to access referenced objects. Otherwise the template code must iterate over all pick objects and compare the publicID in combination with a linear search which is quite slow for larger events.


The current event ID after cleaning invalid characters. That ID is used as event folder name and all event ID depending filenames.


The relative path to the site index file. This can be different according to the templates rendered. If paths are required this variable should be prepended.

<a href="{{ ROOT_URL }}index.html">Home</a>

The path to the static files according to staticURL.

<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/page.css">

The path and filename of the current XML file being processed.


The following images show the different generated pages with the default templates.


Index page with event map


Index page


Event overview


Event arrivals


Event quality


Browser index


Browser page for one year


Browser page for one month


Browser page for one day


Search page

Web Server Integration

EQEvents has been deployed using NGINX or Apache. If unsure which web server to use then select NGINX because this is the most lightweight setup. Since EQEvents by default only consists of static pages the web server integration is straight forward. You may either decide to

  1. generate the pages directly into the web server html directory by setting outputDirectory to e.g., /usr/share/nginx/html/eqevents (NGINX) or /var/www/html/eqevents (Apache) or

  2. you use a softlink to point from inside the html directory to the default EQEvents output directory:

ln -s /home/sysop/seiscomp/var/lib/eqevents/pages /usr/share/nginx/html/eqevents

In case of (1.) make sure that the EQEvents system user, probably sysop, is allowed to write to the html directory. In case of (2.) the x access right must be set for the web server group and for all directories on the path. Also security modules like SELinux might prevent access of the web server process to the user directory. If this is the case use following command to grant those access rights:

chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/etc/global.cfg
chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/etc/eqevents.cfg
chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/etc/defaults/global.cfg
chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/etc/defaults/eqevents.cfg
chcon -Rv --type=httpd_sys_content_t /home/sysop/seiscomp/var/lib/eqevents/pages
chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/var/lib/eqevents/eqevents.db
chcon -Rv --type=httpd_sys_content_t /home/sysop/seiscomp/share/eqevents/templates
chcon -v --type=httpd_sys_content_t /home/sysop/seiscomp/share/eqevents/search-wsgi.py
chcon -Rv --type=texrel_shlib_ti /home/sysop/seiscomp/lib
#setsebool -P httpd_read_user_content 1

Dynamic Content - The Search and Feedback Plugins

The search and the feedback plugin require a WSGI module to generate dynamic content. The installation depends on the web server you selected and is covered different section

NGINX (Gunicorn)

  1. Add the search or feedback plugin to processingPlugins.

  2. Install gunicorn

    python3 -m pip install --user gunicorn
  3. Copy the relevant parts of the server and upstream directives from $SEISCOMP_ROOT/share/eqevents/examples/nginx-gunicorn.conf to your

    • /etc/nginx/nginx.conf or

    • /etc/nginx/sites-available/YOUR-VHOST.conf in case you are using a virtual host setup

  4. Copy the Gunicorn configuration file to the EQEvents base directory:

    cd $SEISCOMP_ROOT/share/eqevents/
    cp examples/search-gunicorn.py .
    #cp examples/feedback-gunicorn.py .

    Adjust the configuration, e.g., logging level, path and format if necessary.

  5. Copy the Gunicorn socket and service systemd configuration:

    sudo cp $SEISCOMP_ROOT/share/gds/web/examples/gunicorn/gunicorn-eqevents-search.* /etc/systemd/system
    #sudo cp $SEISCOMP_ROOT/share/gds/web/examples/gunicorn/gunicorn-eqevents-feedback.* /etc/systemd/system

    Adjust the user, group, or WorkingDirectory variables if necessary. Change type depending on your Gunicorn version. Then enable and start the service:

    sudo systemctl enable gunicorn-eqevents-search
    sudo systemctl start gunicorn-eqevents-search
    #sudo systemctl enable gunicorn-eqevents-feedback
    #sudo systemctl start gunicorn-eqevents-feedback
  6. Test the NGINX configuration:

    sudo nginx -t
  7. Enable and start NGINX:

    sudo systemctl enable nginx
    sudo systemctl start nginx

Trouble shooting

  • Check if the socket file /var/run/gunicorn-eqevents-{search,feedback}.sock was created and ensure that the NGINX user (nginx or www-data) has write access to this file

  • Make a request directly at the socket:

    sudo -u nginx curl --unix-socket /var/run/gunicorn-eqevents-search.sock http
  • By default Gunicorn logs to $HOME/.seiscomp/log/eqevents-web/{search,feedback}-{access,error}.log

  • Reload gunicorn-eqvents-{search,feedback} service after modifications to your $SEISCOMP_ROOT/share/gds/{search,feedback}-gunicorn.py

  • Reload systemd configuration after modifications to systemd service and socket files: sudo systemctl daemon-reload

  • Reload the NGINX server configuration: sudo nginx -t && sudo systemctl reload nginx

Apache (WSGI)

  1. Add the search or feedback plugin to processingPlugins.

  2. Install and enable mod_wsgi

    a2enmod wsgi
  3. Configure WSGI handler, e.g., in /etc/apache2/sites-available/eqevents.conf

    WSGIScriptAlias /eqevents/search /home/sysop/seiscomp/share/eqevents/search-wsgi.py
    #WSGIScriptAlias /eqevents/search /home/sysop/seiscomp/share/eqevents/feedback-wsgi.py
    WSGIPythonPath /home/sysop/seiscomp/lib/python
    WSGIDaemonProcess eqevents processes=2 threads=1 python-path=/home/sysop/seiscomp/lib/python
    WSGIProcessGroup eqevents
  4. Configure access to static content (optional, same file as above)

    <Location "/eqevents">
      Options -Indexes
      SetHandler None
      Require all granted
  5. Set environment variables

    Ubuntu: /etc/apache2/envvars

    export LD_LIBRARY_PATH=/home/sysop/seiscomp/lib:$LD_LIBRARY_PATH
    export SEISCOMP_ROOT=/home/sysop/seiscomp

    RHEL: /etc/sysconfig/httpd

  6. Enable site

    a2ensite eqevents
  7. Restart Apache

Module Configuration


eqevents inherits global options.


Modules/plugins may require a license file. The default path to license files is @DATADIR@/licenses/ which can be overridden by global configuration of the parameter gempa.licensePath. Example:

gempa.licensePath = @CONFIGDIR@/licenses

Default: @ROOTDIR@/var/lib/eqevents/eqevents.db

Type: path

Path to the sqlite3 database file.


Default: @DATADIR@/eqevents/templates/default

Type: path

Directory to read templates from.


Default: @ROOTDIR@/var/lib/eqevents/pages

Type: path

Target directory for generated web pages.


Default: @ROOTDIR@/var/lib/eqevents/spool

Type: path

Spooler directory to read content files from.


Default: 10

Unit: s

Type: int

Polling interval in seconds the spooler will scan the service directory for new files.


Default: false

Type: boolean

Defines whether to backup the input XML in the output HTML directory per event as [id].xml. The XML backup allows easy reprocessing of the Web page in case of template changes, see ‘--reprocess’ command line option.


Default: static/

Type: string

URL prefix for static files used in the templates. Can be used as {{ STATIC_URL }} in templates.


Default: true

Type: boolean

Enables arrival output as part of the event detail page.


Default: 50

Type: int

Number of events for the index page.


Type: int

Events of this number of past days for the index page. If this parameter is not configured then numberOfIndexEvents is in effect. If this parameter is configured then it takes precedence over numberOfIndexEvents.


Default: 0

Type: int

Maximum number of days to keep events for. Older events are removed. A value of 0 or below means unlimited.


Default: false

Type: boolean

An event might be marked as fake event using the event type ‘not existing’ or ‘other’. Set this parameter to ‘true’ to process fake events respectively to prevent them from being deleted.


Default: false

Type: boolean

The GDS uses the ‘match’ flag to signal whether an event solution fulfilled the dissemination criteria. E.g. an updated event revision might correct the epicenter to a point outside the area of interest. Set this parameter to ‘true’ to process not matching events respectively to prevent them from being deleted.


Default: browser, plots

Type: list:string

List of eqevents processing plugins.


Default: false

Type: boolean

Include origin author information in generated web pages.


filter.* Parameters which filter the event data processed by the various plugins.


Type: double

Hides arrivals having a weight smaller than the configured threshold. To remove unused phases set a value of >0.


gds.* Configuration parameters of the GDS plugin to generate gds reports. To use that plugin, add ‘gds’ to the list of processing plugins.


Type: string

GDS database URL used to report back the processing state, e.g. ‘mysql://user:pass@localhost/gds’.


gis.* Configuration parameters of the GIS plugin to generate map files. To use that plugin, add ‘gis’ to the list of processing plugins.


Default: http://localhost:20001

Type: string

URL of the GIS RESTful API.


Default: 10

Type: int

Defines the timeout for GIS requests. If the timeout expires and GIS did not return an empty image is generated.


Default: false

Type: boolean

By default the image is requested from the GIS using the HTTP-GET mothod along with key event parameters. If set to ‘true’ the HTTP-POST method is used instead to transfer the whole event XML. This allows the GIS to render an image with even more information, like used stations or moment tensor solutions.


rss.* Configuration parameters of the RSS plugin. To use that plugin, add ‘rss’ to the list of processing plugins.


Default: 1

Type: int

Number of (last) days to generate the RSS feed for.


Default: EQ Events RSS Channel - last ${days}

Type: string

Title of the RSS feed. The variable ‘${days}’ is replaced by the string containing the number of days configured in the ‘rss.days’ parameter, e.g. ‘2 days’.


Default: Real-time earthquake locations

Type: string

Description of RSS feed that is copied to the description tag of the RSS XML.

Default: https://localhost

Type: string

URL prefix for each event detail page. EQEvents just deals with relative paths but to transform an RSS item link into an absolute URL this prefix is required.


notification.* Configuration parameters of the NOTIFICATION plugin to send notifications to a socket.io-server. To use that plugin, add ‘notification’ to the list of processing plugins.


Default: localhost

Type: string

Hostname of the Socket.IO server.


Default: 8000

Type: int

Port of the Socket.IO server.


Default: /event

Type: string

Socket.IO namespace.


leaflet.* Configuration parameters for the Leaflet map plugin that renders an interactive map on the index page.


leaflet.init.* By default the map view is set to the bounds of the current event list. This configuration group allows to define a fix coordinate and zoom level for the initial map view.


Unit: degrees

Type: double

Initial latitude to center the map view.


Unit: degrees

Type: double

Initial longitude to center the map view.


Default: 3

Type: int

Initial zoom level for the map view.


leaflet.tile.* Parmeters controlling the map tile layer.


Default: http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png

Type: string

Tile URL. See https://leafletjs.com/reference-1.7.1.html#tilelayer for a list of supported placeholders.


Default: "Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors"

Type: string

Tile attribution string displayed on the bottom right corner.


Default: 18

Type: int

Maximum available zoom level.


leaflet.control.* Defines available map controls typically displayed at bottom left map corner.


Default: true

Type: boolean

Adds a scale showing the map resolution in meter or kilometer at the map center.


Default: false

Type: boolean

Adds a scale showing the map resolution in feet or miles at the map center.


Default: true

Type: boolean

Adds a control showing the geo location under the mouse cursor.


search.* The search plugin provides a page to configure a search filter.


Default: 100

Type: int

The maximum number of search results.


Default: km

Type: string

The unit used for the radius of the circular region filter. This can either be ‘km’, ‘mi’ or ‘deg’. Conversion constants used: 1 mile = 1.609344 kilometers, 1 degree = 111.195079734632 kilometers.


Default: true

Type: boolean

Enables interactive map region selection.


feedback.* The feedback plugin implemets a email feedback form.


Type: string

The email’s ‘From’ address (mandatory).


Type: string

The email’s ‘To’ address (mandatory).


Default: EQEvents feedback

Type: string

The email’s ‘Subject’.


Default: localhost

Type: string

SMTP host.


Default: 25

Type: int

SMTP port.


Type: string

User in case the SMTP server requires authorization.


Type: string

Password in case the SMTP server requires authorization.


Default: false

Type: boolean

Use StartTLS.


Default: false

Type: boolean

Use Secure Socket Layer (SSL).


shakemap.* The shakemap plugin adds a shake map image to the event overview page. The image is generated by an external application, e.g. autosigma.


Default: autosigma --ep

Type: string

Command generating the result file, invoked with the location of the SC3 XML file as last paramter.


Default: 5.0

Type: float

Minimum magnitude to trigger shake map generation.


Default: @ROOTDIR@/var/sigma/incidents/grid-mmi.png

Type: string

Expected location of the result file.

Command-Line Options




-i, --input string

Input file to be processed immediately. EQEvents will not change into spooler mode after processing this file.


Reprocess event detail pages and index pages for events found in database. This mode requires backupXML being enabled.


Reprocess index pages for events found in database.