diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst
index d117e427a77d16a93929202c2d4fdd61432f1585..c9eb574f51815481845fda55fadcb1d6ae101b7b 100644
--- a/docs/gettingstarted.rst
+++ b/docs/gettingstarted.rst
@@ -120,5 +120,73 @@ Part 2 : Training a Simple DQN Agent
 Part 3 : Customizing Observations and Level Generators
 --------------
 
+Example code for generating custom observations given a RailEnv and to generate 
+random rail maps are available in examples/custom_observation_example.py and 
+examples/custom_railmap_example.py .
 
+Custom observations can be produced by deriving a new object from the 
+core.env_observation_builder.ObservationBuilder base class, for example as follows:
 
+.. code-block:: python
+
+    class CustomObs(ObservationBuilder):
+        def __init__(self):
+            self.observation_space = [5]
+    
+        def reset(self):
+            return
+    
+        def get(self, handle):
+            observation = handle*np.ones((5,))
+            return observation
+
+It is important that an observation_space is defined with a list of dimensions 
+of the returned observation tensors. get() returns the observation for each agent, 
+of handle 'handle'.
+
+A RailEnv environment can then be created as usual:
+
+.. code-block: python
+
+    env = RailEnv(width=7,
+                  height=7,
+                  rail_generator=random_rail_generator(),
+                  number_of_agents=3,
+                  obs_builder_object=CustomObs())
+
+As for generating custom rail maps, the RailEnv class accepts a rail_generator 
+argument that must be a function with arguments 'width', 'height', 'num_agents', 
+and 'num_resets=0', and that has to return a GridTransitionMap object (the rail map),
+and three lists of tuples containing the (row,column) coordinates of each of 
+num_agent agents, their initial orientation (0=North, 1=East, 2=South, 3=West), 
+and the position of their targets.
+
+For example, the following custom rail map generator returns an empty map of 
+size (height, width), with no agents (regardless of num_agents):
+
+.. code-block: python
+
+    def custom_rail_generator():
+        def generator(width, height, num_agents=0, num_resets=0):
+            rail_trans = RailEnvTransitions()
+            grid_map = GridTransitionMap(width=width, height=height, transitions=rail_trans)
+            rail_array = grid_map.grid
+            rail_array.fill(0)
+    
+            agents_positions = []
+            agents_direction = []
+            agents_target = []
+    
+            return grid_map, agents_positions, agents_direction, agents_target
+        return generator
+
+It is worth to note that helpful utilities to manage RailEnv environments and their 
+related data structures are available in 'envs.env_utils'. In particular, 
+envs.env_utils.get_rnd_agents_pos_tgt_dir_on_rail is fairly handy to fill in 
+random (but consistent) agents along with their targets and initial directions, 
+given a rail map (GridTransitionMap object) and the desired number of agents:
+
+.. code-block: python
+    agents_position, agents_direction, agents_target = get_rnd_agents_pos_tgt_dir_on_rail(
+        rail_map,
+        num_agents)