diff --git a/nb-configuration.xml b/nb-configuration.xml
index 2f11ad2cceb58419d0c43844e6368745831a97c2..2f83dadc32daaac6803a54762414e0936fc975ed 100755
--- a/nb-configuration.xml
+++ b/nb-configuration.xml
@@ -27,5 +27,6 @@ Any value defined here will override the pom.xml file value but is only applicab
         <org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language>
         <org-netbeans-modules-maven-jaxws._5f_C_5f_DMIWeatherService_2e_svc>https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?wsdl</org-netbeans-modules-maven-jaxws._5f_C_5f_DMIWeatherService_2e_svc>
         <netbeans.compile.on.save>none</netbeans.compile.on.save>
+        <netbeans.hint.jdkPlatform>JDK_1.8_SUN</netbeans.hint.jdkPlatform>
     </properties>
 </project-shared-configuration>
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
index 41fe540841ec985c4c17620ffe5780219502eba9..84296265272a85b910773c9e5f1517938f6b7d27 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.stream.Collectors;
 import javax.ejb.Stateless;
 import javax.persistence.EntityManager;
 import javax.persistence.NoResultException;
@@ -509,7 +510,7 @@ public class ObservationBean {
             Integer organizationId, 
             Integer pestId, 
             Integer cropId, 
-            Integer cropCategoryId,
+            List<Integer> cropCategoryId,
             Date from, 
             Date to
     ) 
@@ -535,12 +536,12 @@ public class ObservationBean {
             sql += "AND crop_organism_id = :cropOrganismId \n";
             parameters.put("cropOrganismId", cropId);
         }
-        else if(cropCategoryId != null && cropCategoryId > 0)
+        else if(cropCategoryId != null && ! cropCategoryId.isEmpty())
         {
-            CropCategory cropCategory = em.createNamedQuery("CropCategory.findByCropCategoryId", CropCategory.class)
-                    .setParameter("cropCategoryId", cropCategoryId)
-                    .getSingleResult();
-            List<Integer> cropIds = Arrays.asList(cropCategory.getCropOrganismIds());
+            List<CropCategory> cropCategories = em.createNamedQuery("CropCategory.findByCropCategoryIds", CropCategory.class)
+                    .setParameter("cropCategoryIds", cropCategoryId)
+                    .getResultList();
+            List<Integer> cropIds = new ArrayList(cropCategories.stream().flatMap(cC->Arrays.asList(cC.getCropOrganismIds()).stream()).collect(Collectors.toSet()));
                     
             sql += "AND crop_organism_id IN (:cropOrganismIds) \n";
             parameters.put("cropOrganismIds", cropIds);
diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java
index a838635aca0edb56fe70647a1302547a930f5cca..c6e4303ba23d639efddd4cd81e407316400745b8 100755
--- a/src/main/java/no/nibio/vips/logic/entity/Observation.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java
@@ -48,6 +48,7 @@ import javax.persistence.OneToMany;
 import javax.validation.constraints.Size;
 import no.nibio.vips.logic.util.GISEntityUtil;
 import no.nibio.vips.gis.GISUtil;
+import no.nibio.vips.logic.entity.rest.ObservationListItem;
 import no.nibio.vips.logic.util.StringJsonUserType;
 import org.hibernate.annotations.Type;
 import org.hibernate.annotations.TypeDef;
@@ -606,4 +607,25 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse
         this.lastEditedByUser = lastEditedByUser;
     }
 
+    public ObservationListItem getListItem(String locale)
+    {
+        // If geoInfo is from POI, need to add observationId
+        if(this.location != null)
+        {
+            this.location.addProperty("observationId", this.getObservationId());
+        }
+        return new ObservationListItem(
+                this.getObservationId(),
+                this.getTimeOfObservation(),
+                this.getOrganismId(),
+                this.getOrganism().getLocalName(locale),
+                this.getCropOrganismId(),
+                this.getCropOrganism().getLocalName(locale),
+                this.location != null ? this.location.getGeoJSON() : this.getGeoinfo(),
+                this.getObservationHeading(),
+                this.getBroadcastMessage(),
+                this.getLocationIsPrivate()
+        );
+    }
+    
 }
diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
index e27300e00d70d5b52769b5847e7572f4e6fa83c6..d047e6dafa7fdb065c2f53ef706da9c5f16f54f3 100755
--- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
+++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
@@ -326,9 +326,13 @@ public class PointOfInterest implements Serializable, Comparable {
     @Transient
     public String getGeoJSON()
     {
-        Map<String, Object> properties = new HashMap<>();
-        properties.put("pointOfInterestId", this.getPointOfInterestId());
-        return this.gisUtil.getGeoJSONFromGeometry(this.getGisGeom(), properties);
+        this.addProperty("pointOfInterestId", this.getPointOfInterestId());
+        return this.gisUtil.getGeoJSONFromGeometry(this.getGisGeom(), this.getProperties());
+    }
+    
+    public void addProperty(String key, Object value)
+    {
+        this.getProperties().put(key, value);
     }
     
     /**
diff --git a/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java b/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..7193b73a1c70fb53d791206fec8a2dc9ca4c9e32
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSLogic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package no.nibio.vips.logic.entity.rest;
+
+import java.util.Date;
+
+/**
+ * @copyright 2018 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class ObservationListItem {
+    private Integer observationId, organismId, cropOrganismId;
+    private Date timeOfObservation;
+    private String organismName, cropOrganismName;
+    private String geoInfo;
+    private String observationHeading;
+    private Boolean broadcastMessage, locationIsPrivate;
+
+    public ObservationListItem(
+            Integer observationId,
+            Date timeOfObservation,
+            Integer organismId,
+            String organismName,
+            Integer cropOrganismId,
+            String cropOrganismName,
+            String geoinfo,
+            String observationHeading,
+            Boolean broadcastMessage,
+            Boolean locationIsPrivate
+    ){
+        this.observationId = observationId;
+        this.timeOfObservation = timeOfObservation;
+        this.organismId = organismId;
+        this.organismName = organismName;
+        this.cropOrganismId = cropOrganismId;
+        this.cropOrganismName = cropOrganismName;
+        this.geoInfo = geoinfo;
+        this.observationHeading = observationHeading;
+        this.broadcastMessage = broadcastMessage;
+        this.locationIsPrivate = locationIsPrivate;
+    }
+    
+    /**
+     * @return the observationId
+     */
+    public Integer getObservationId() {
+        return observationId;
+    }
+
+    /**
+     * @param observationId the observationId to set
+     */
+    public void setObservationId(Integer observationId) {
+        this.observationId = observationId;
+    }
+
+    /**
+     * @return the timeOfObservation
+     */
+    public Date getTimeOfObservation() {
+        return timeOfObservation;
+    }
+
+    /**
+     * @param timeOfObservation the timeOfObservation to set
+     */
+    public void setTimeOfObservation(Date timeOfObservation) {
+        this.timeOfObservation = timeOfObservation;
+    }
+
+    /**
+     * @return the organismName
+     */
+    public String getOrganismName() {
+        return organismName;
+    }
+
+    /**
+     * @param organismName the organismName to set
+     */
+    public void setOrganismName(String organismName) {
+        this.organismName = organismName;
+    }
+
+    /**
+     * @return the cropOrganismName
+     */
+    public String getCropOrganismName() {
+        return cropOrganismName;
+    }
+
+    /**
+     * @param cropOrganismName the cropOrganismName to set
+     */
+    public void setCropOrganismName(String cropOrganismName) {
+        this.cropOrganismName = cropOrganismName;
+    }
+
+    /**
+     * @return the geoInfo
+     */
+    public String getGeoInfo() {
+        return geoInfo;
+    }
+
+    /**
+     * @param geoInfo the geoInfo to set
+     */
+    public void setGeoInfo(String geoInfo) {
+        this.geoInfo = geoInfo;
+    }
+
+    /**
+     * @return the observationHeading
+     */
+    public String getObservationHeading() {
+        return observationHeading;
+    }
+
+    /**
+     * @param observationHeading the observationHeading to set
+     */
+    public void setObservationHeading(String observationHeading) {
+        this.observationHeading = observationHeading;
+    }
+
+    /**
+     * @return the organismId
+     */
+    public Integer getOrganismId() {
+        return organismId;
+    }
+
+    /**
+     * @param organismId the organismId to set
+     */
+    public void setOrganismId(Integer organismId) {
+        this.organismId = organismId;
+    }
+
+    /**
+     * @return the cropOrganismId
+     */
+    public Integer getCropOrganismId() {
+        return cropOrganismId;
+    }
+
+    /**
+     * @param cropOrganismId the cropOrganismId to set
+     */
+    public void setCropOrganismId(Integer cropOrganismId) {
+        this.cropOrganismId = cropOrganismId;
+    }
+
+    /**
+     * @return the broadcastMessage
+     */
+    public Boolean getBroadcastMessage() {
+        return broadcastMessage;
+    }
+
+    /**
+     * @param broadcastMessage the broadcastMessage to set
+     */
+    public void setBroadcastMessage(Boolean broadcastMessage) {
+        this.broadcastMessage = broadcastMessage;
+    }
+
+    /**
+     * @return the locationIsPrivate
+     */
+    public Boolean getLocationIsPrivate() {
+        return locationIsPrivate;
+    }
+
+    /**
+     * @param locationIsPrivate the locationIsPrivate to set
+     */
+    public void setLocationIsPrivate(Boolean locationIsPrivate) {
+        this.locationIsPrivate = locationIsPrivate;
+    }
+}
diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java
index c47fed1d2da6cff7ae3486c887a31cffed17deeb..5e171c638249e5ec2e992a91839677efe1647224 100755
--- a/src/main/java/no/nibio/vips/logic/service/LogicService.java
+++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java
@@ -56,7 +56,6 @@ import no.nibio.vips.logic.entity.ForecastConfiguration;
 import no.nibio.vips.logic.entity.ForecastModelConfiguration;
 import no.nibio.vips.logic.entity.Message;
 import no.nibio.vips.logic.entity.MessageTag;
-import no.nibio.vips.logic.entity.Observation;
 import no.nibio.vips.logic.entity.Organism;
 import no.nibio.vips.logic.entity.Organization;
 import no.nibio.vips.logic.entity.PointOfInterest;
diff --git a/src/main/java/no/nibio/vips/logic/service/ObservationService.java b/src/main/java/no/nibio/vips/logic/service/ObservationService.java
index 24a81647701723b8cf01dc4beba02e7d4c5dde42..7e84c3295bcc402fd6f6566800f4554e0f5bfe64 100755
--- a/src/main/java/no/nibio/vips/logic/service/ObservationService.java
+++ b/src/main/java/no/nibio/vips/logic/service/ObservationService.java
@@ -26,6 +26,8 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -56,20 +58,24 @@ public class ObservationService {
     @Context
     private HttpServletRequest httpServletRequest;
     
-    /**
+    /*
      * NOTE TO SELF
      * How to query for observations within a bounding box
      * Select * from gis where ST_Intersects(
      *   ST_SetSRID(ST_MakeBox2D(ST_MakePoint(2.9004, 57.7511), ST_MakePoint(32.4316, 71.3851)),4326),
      *   gis_geom);
      * First point is SW, last is NE (but could be anything?)
+    */
+    
+    /**
+     * 
      * @param organizationId
      * @param pestId
      * @param cropId
      * @param cropCategoryId
      * @param from
      * @param to
-     * @return 
+     * @return Observation objects with all data (full tree)
      */
     @GET
     @Path("filter/{organizationId}")
@@ -79,11 +85,74 @@ public class ObservationService {
             @PathParam("organizationId") Integer organizationId,
             @QueryParam("pestId") Integer pestId,
             @QueryParam("cropId") Integer cropId,
-            @QueryParam("cropCategoryId") Integer cropCategoryId,
+            @QueryParam("cropCategoryId") List<Integer> cropCategoryId,
             @QueryParam("from") String fromStr,
             @QueryParam("to") String toStr
             
     )
+    {
+        return Response.ok().entity(getFilteredObservationsFromBackend(
+                organizationId,
+                pestId,
+                cropId,
+                cropCategoryId,
+                fromStr,
+                toStr
+        )).build();
+    }
+    
+    /**
+     * 
+     * @param organizationId
+     * @param pestId
+     * @param cropId
+     * @param cropCategoryId
+     * @param from
+     * @param to
+     * @return Observation objects for which the user is authorized to observe with properties relevant for lists
+     */
+    @GET
+    @Path("list/filter/{organizationId}")
+    @GZIP
+    @Produces("application/json;charset=UTF-8")
+    public Response getFilteredObservationListItems(
+            @PathParam("organizationId") Integer organizationId,
+            @QueryParam("pestId") Integer pestId,
+            @QueryParam("cropId") Integer cropId,
+            @QueryParam("cropCategoryId") List<Integer> cropCategoryId,
+            @QueryParam("from") String fromStr,
+            @QueryParam("to") String toStr,
+            @QueryParam("userUUID") String userUUID
+            
+    )
+    {
+        VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user");
+        if(user == null && userUUID != null)
+        {
+            user = SessionControllerGetter.getUserBean().findVipsLogicUser(UUID.fromString(userUUID));
+        }
+        return Response.ok().entity(
+                getFilteredObservationsFromBackend(
+                        organizationId,
+                        pestId,
+                        cropId,
+                        cropCategoryId,
+                        fromStr,
+                        toStr,
+                        user
+                ).stream().map(obs -> obs.getListItem("nb")).collect(Collectors.toList())
+        ).build();
+    }
+            
+            
+    private List<Observation> getFilteredObservationsFromBackend(
+            Integer organizationId,
+            Integer pestId,
+            Integer cropId,
+            List<Integer> cropCategoryId,
+            String fromStr,
+            String toStr
+    )
     {
         SimpleDateFormat format = new SimpleDateFormat(Globals.defaultDateFormat);
         //TODO Set correct timeZone!!!
@@ -96,7 +165,7 @@ public class ObservationService {
         }
         catch(ParseException ex){ System.out.println("ERROR");}
                 
-        List<Observation> filteredObservations = SessionControllerGetter.getObservationBean().getFilteredObservations(
+        return SessionControllerGetter.getObservationBean().getFilteredObservations(
             organizationId,
             pestId,
             cropId,
@@ -104,7 +173,7 @@ public class ObservationService {
             from,
             to
         );
-        return Response.ok().entity(filteredObservations).build();
+        
     }
     
     @GET
@@ -115,7 +184,7 @@ public class ObservationService {
             @PathParam("organizationId") Integer organizationId,
             @QueryParam("pestId") Integer pestId,
             @QueryParam("cropId") Integer cropId,
-            @QueryParam("cropCategoryId") Integer cropCategoryId,
+            @QueryParam("cropCategoryId") List<Integer> cropCategoryId,
             @QueryParam("from") String fromStr,
             @QueryParam("to") String toStr
             
@@ -325,5 +394,23 @@ public class ObservationService {
         return firstObsTime != null ? Response.ok().entity(firstObsTime).build()
                 : Response.status(404).entity("No observations of organism with id=" + organismId).build();
     }
+
+    private List<Observation> getFilteredObservationsFromBackend(Integer organizationId, Integer pestId, Integer cropId, List<Integer> cropCategoryId, String fromStr, String toStr, VipsLogicUser user) {
+        List<Observation> filteredObservations = this.getFilteredObservationsFromBackend(organizationId, pestId, cropId, cropCategoryId, fromStr, toStr);
+        // If user is not logged in, return only the publicly available observations
+        if(user == null)
+        {
+            return filteredObservations.stream().filter(obs->obs.getBroadcastMessage()).collect(Collectors.toList());
+        }
+        // Else: If superuser: Return everything
+        if(user.isSuperUser() || user.isOrganizationAdmin())
+        {
+            return filteredObservations;
+        }
+        // Else: This is a registered user without special privileges. Show public observations + user's own
+        List<Observation> retVal = filteredObservations.stream().filter(obs->obs.getBroadcastMessage()).collect(Collectors.toList());
+        retVal.addAll(SessionControllerGetter.getObservationBean().getObservationsForUser(user));
+        return retVal;
+    }
     
 }